iOS面试题汇总+答案

前言:

最近把 iOS 面试中可能会遇到的问题整理了一番, 题目大部分是网上收录的, 方便自己巩固复习, 也分享给大家; 希望对大家有所帮助!

一、OC部分

1.什么是runtime?

1.runtime 运行时机制,是一套比较底层的纯 C 语言 API , 属于1个 C 语言库, 包含了很多底层的 C 语言 API 。(引入 <objc/runtime.h> 或者 <objc/message.h> )
2.程序运行过程时,我们平时编写的 OC 代码, 其实最终都是转成了 runtime 的 C 语言代码。
3.在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才能根据函数的名称找到对应的函数来调用。

2.runtime 是干什么用的?使用场景是什么?

1.OC的动态性就是由Runtime来支撑和实现的,Runtime是一套C语言的API,封装了很多动态性相关的函数
2.利用关联对象(AssociatedObject)给分类添加属性
3.遍历类的所有成员变量(修改textfield的占位文字颜色、字典转模型、自动归档解档)
4.利用消息转发机制解决方法找不到的异常问题
5.KVC、KVO都是基于runtime实现的。

3.讲一下 OC 的消息机制

1.当向一个对象发送消息时,objc_msgSend 方法根据对象的 isa 指针找到对象的类,然后在类的调度表(dispatch table)中查找 selector。
2.如果无法找到 selector,objc_msgSend 通过指向父类的指针找到父类,并在父类的调度表(dispatch table)中查找 selector,以此类推直到 NSObject 类。
3.一旦查找到 selector,objc_msgSend 方法根据调度表的内存地址调用该实现。
4.通过这种方式,message 与方法的真正实现才在执行阶段进行绑定。
5.为了保证消息发送与执行的效率,系统会将全部 selector 和使用过的方法的内存地址缓存起来。
6.每个类都有一个独立的缓存,缓存包含有当前类自己的 selector 以及继承自父类的 selector。
7.查找调度表(dispatch table)前,消息发送系统首先检查 receiver 对象的缓存;缓存命中的情况下,消息发送(messaging)比直接调用方法(function call)只慢一点点。

4.动态绑定

1,在运行时确定要调用的方法,动态绑定将调用方法的确定也推迟到运行时。
2.在编译时,方法的调用并不和代码绑定在一起,只有在消实发送出来之后,才确定被调用的代码。
3.通过动态类型和动态绑定技术,您的代码每次执行都可以得到不同的结果。
4.运行时负责确定消息的接收者和被调用的方法;运行时的消息分发机制为动态绑定提供支持。
5.当您向一个动态类型确定了的对象发送消息时,运行环境系统会通过接收者的 isa 指针定位对象的类,并以此为起点确定被调用的方法,方法和消息是动态绑定的。而且,您不必在 Objective-C 代码中做任何工作,就可以自动获取动态绑定的好处。
6.您在每次发送消息时,特别是当消息的接收者是动态类型已经确定的对象时,动态绑定就会例行而透明地发生。

5.讲一下isa指针

1.isa 等价于 is kind of
实例对象 isa 指向类对象
类对象 isa 指向元类对象
元类对象的 isa 指向元类的基类

6.iOS中实现多线程的几种方案,各自有什么特点?

1.NSThread 面向对象的,需要程序员手动创建线程,但不需要手动销毁。子线程间通信很难。
2.GCD c语言,充分利用了设备的多核,自动管理线程生命周期。比NSOperation效率更高。
3.NSOperation 基于gcd封装,更加面向对象,比gcd多了一些功能。

7.GCD执行原理?

1.GCD有一个底层线程池,这个池中存放的是一个个的线程。之所以称为“池”,很容易理解出这个“池”中的线程是可以重用的,当一段时间后这个线程没有被调用胡话,这个线程就会被销毁。注意:开多少条线程是由底层线程池决定的(线程建议控制再3~5条),池是系统自动来维护,不需要我们程序员来维护(看到这句话是不是很开心?) 而我们程序员需要关心的是什么呢?我们只关心的是向队列中添加任务,队列调度即可。

2.如果队列中存放的是同步任务,则任务出队后,底层线程池中会提供一条线程供这个任务执行,任务执行完毕后这条线程再回到线程池。这样队列中的任务反复调度,因为是同步的,所以当我们用currentThread打印的时候,就是同一条线程。
如果队列中存放的是异步的任务,(注意异步可以开线程),当任务出队后,底层线程池会提供一个线程供任务执行,因为是异步执行,队列中的任务不需等待当前任务执行完毕就可以调度下一个任务,这时底层线程池中会再次提供一个线程供第二个任务执行,执行完毕后再回到底层线程池中。

3.这样就对线程完成一个复用,而不需要每一个任务执行都开启新的线程,也就从而节约的系统的开销,提高了效率。在iOS7.0的时候,使用GCD系统通常只能开58条线程,iOS8.0以后,系统可以开启很多条线程,但是实在开发应用中,建议开启线程条数:35条最为合理。

8.多个网络请求完成后执行下一步

1.使用GCD的dispatch_group_t
每次网络请求前先dispatch_group_enter(进入),请求回调后再dispatch_group_leave(离开),enter和leave必须配合使用,有几次enter就要有几次leave,否则group会一直存在。
当所有enter的block都leave后,会执行dispatch_group_notify的block。
2.使用GCD的信号量dispatch_semaphore_t

9.异步操作两组数据时, 执行完第一组之后, 才能执行第二组

这里使用dispatch_barrier_async栅栏方法即可实现

10.什么情况使用 weak 关键字,相比 assign 有 什么不同?

1.在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决, 比如:delegate 代理属性, 自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性一般也使用 weak;当然,也可以使用 strong,但是建议使用 weak

2.weak 策略在属性所指的对象遭到摧毁时,系统会将 weak 修饰的属性对象的指针指 向 nil,在 OC 给 nil 发消息是不会有什么问题的; 如果使用 assign 策略在属性所指 的对象遭到摧毁时,属性对象指针还指向原来的对象,由于对象已经被销毁,这时候就产生了野指针,如果这时候在给此对象发送消息,很容造成程序奔溃 assigin 可以用于修饰非 OC 对象,而 weak 必须用于 OC 对象

11.怎么用 copy 关键字?

1.NSString、NSArray、NSDictionary 等等经常使用 copy 关键字,是因为他们有对应 的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,为确保 对象中的属性值不会无意间变动,应该在设置新属性值时拷贝一份,保护其封装性

2.block 也经常使用 copy 关键字,方法内部的 block 默认是 在栈区的,使用 copy 可以把它放到堆区.

12.怎么样优化APP启动速度?

1.在main函数执行之前

1.1尽量删除一些不必要的系统文件和第三方库。
1.2尽量删除一些不必要的.h .m 文件。
1.3尽量不要在类的load函数放入大量初始化信息,这样会延迟加载时间。

2.didfinishlauch函数到第一个主界面加载显示阶段

2.1减少不必要的网络请求。
2.2较少不必要的数据初始化操作,尽量写成懒加载
2.3减少一些第三方sdk的初始化和版本检测相关代码

13.UIView 和 CALayer 的区别?

UIView 是 CALayer 的 delegate,UIView 可以响应事件,而 CA Layer 则不能。

14.KVC 的主要应用的场景与注意的事项

KVC全称(key-Value coding)称呼为键值编码,在iOS开发中。允许开发者通过key名直接访问对象的属性,或者给对象的属性赋值。需要调用明确的存取方法,这样就可以在运行时动态访问和修改对象的属性,而不是在编译时确定。

15.iOS类别的作用?继承和类别在实现中有何区别?

category 可以在不获悉,不改变原来代码的情况下往里面添加新的方法,只能添加,不能删除修改。 并且如果类别和原来类中的方法产生名称冲突,则类别将覆盖原来的方法,因为类别具有更高的优先级。
类别主要有3个作用:
(1)将类的实现分散到多个不同文件或多个不同框架中。
(2)创建对私有方法的前向引用。
(3)向对象添加非正式协议。 继承可以增加,修改或者删除方法,并且可以增加属性。
生效周期:Category是runtime,Extension是编译时。
Category可以为系统类添加分类,Extension不能。
文件:Category是有h声明和m实现,Extension直接写在宿主.m文件,只有h声明。
Category只能扩充方法,不能扩充成员变量和属性,因为成员变量是编译时的,属性会在编译时自动生成setter和getter,但Category是runtime。

16.KVO是什么?简述KVO的实现原理。KVO是否能监听数组?如何实现?

KVO(键值观察):它可以使对象获取其他对象属性变化的通知机制。

调用KVC会触发KVO。

KVO使用了isa-swizzling方式结合RunTime动态性,在给对象首次添加KVO时,RunTime会动态创建被监听对象的子类(NSKVONofifying_ClassName),然后实现setter,class,dealloc,_isKVOA方法,并在setter方法中实现对应通知机制。接下来将被监听对象isa指向动态创建的子类。使用KVC修改属性值时,会调用动态创建的子类中对应setter方法,触发通知机制,如此便实现了KVO。

KVO监听数组需实现 NSMutableArray 的增删改操作遵从 KVC 的规则:

增: -insertObject:inAtIndex: 或者 -insert:atIndexes:
删: -removeObjectFromAtIndex: 或者 -removeAtIndexes:
改:-replaceObjectInAtIndex:withObject: 或者 -replaceAtIndexes:with:
并将这些接口暴露给调用者,在对数组进行操作时需使用上述实现的接口。

16.如何理解RunLoop

在主线程中默认开启RunLoop,它不断地监听系统事件,如触摸事件、定时器事件等,一旦有事件发生,就会通知相应的处理方法来处理该事件。

Swift相关:

1.类(class)和 结构体(struct)有什么区别?

Struct不支持继承,Class支持继承
Struct是值类型,Class是引用类型
Struct使用let创建不可变,Class使用let创建可变
Struct无法修改自身属性值,函数需要添加mutating关键字
Struct不需要deinit方法,因为值类型不关系引用计数,Class需要deinit方法
Struct初始化方法是基于属性的

2.map、filter、reduce 的作用

map 用于映射, 可以将一个列表转换为另一个列表
filter 用于过滤, 可以筛选出想要的元素
reduce 合并

3.String 与 NSString 的关系与区别

NSString 与 String 之间可以随意转换,
String 是结构体, 值类型, NSString 是类, 引用类型.
通常, 没必要使用 NSString 类, 除非你要使用一些特有方法, 例如使用 pathExtension 属性

4.什么是高阶函数

一个函数如果可以以某一个函数作为参数, 或者是返回值, 那么这个函数就称之为高阶函数, 如 map, reduce, filter

5.逃逸闭包,非逃逸闭包,尾随闭包

1.非逃逸闭包:一个接受闭包作为参数的函数,闭包是在这个函数结束前内被调用,即可以理解为闭包是在函数作用域结束前被调用

1、不会产生循环引用,因为闭包的作用域在函数作用域内,在函数执行完成后,就会释放闭包捕获的所有对象
2、针对非逃逸闭包,编译器会做优化:省略内存管理调用

2.逃逸闭包:一个接受闭包作为参数的函数,逃逸闭包可能会在函数返回之后才被调用,即闭包逃离了函数的作用域

1、可能会产生循环引用,因为逃逸闭包中需要显式的引用self(猜测其原因是为了提醒开发者,这里可能会出现循环引用了),而self可能是持有闭包变量的(与OC中block的的循环引用类似)
2、一般用于异步函数的返回,例如网络请求

3.尾随闭包:函数的最后一个参数是闭包,就叫做尾随闭包,可以增强可读性

6.Swift比Objective-C有什么优势?

1、Swift是强类型(静态)语言,有类型推断,Objective-C弱类型(动态)语言
2、Swift面向协议编程,Objective-C面向对象编程
3、Swift注重值类型,Objective-C注重引用类型
4、Swift支持泛型,Objective-C只支持轻量泛型(给集合添加泛型)
5、Swift支持静态派发(效率高)、动态派发(函数表派发、消息派发)方式,Objective-6、C支持动态派发(消息派发)方式
7、Swift支持函数式编程(高阶函数)
8、Swift的协议不仅可以被类实现,也可以被Struct和Enum实现
9、Swift有元组类型、支持运算符重载
10、Swift支持命名空间
11、Swift支持默认参数
12、Swift比Objective-C代码更简洁

7.Swift的可选项类型(Optionals)介绍

Swift引入了可选项类型,用于处理变量值不存在的情况。Optionals类似于OC中指向nil的指针,但是适用于所有数据类型,而非仅仅局限于类,Optionals相比于OC中的nil指针,更加安全和简明,并且也是Swift诸多最强大功能的核心。

8.Swift中的 !和 ?

这两个符号是用来标记这个变量的值是否可选,!表示可选变量必须保证转换能够成功,否则报错,但定义的变量可以直接使用;?表示可选变量即使转换不成功也不会报错,变量值为nil,如果转换成功,要使用该变量时,后面需要加!进行修饰。

9.讲讲Swift的派发机制

函数的派发机制:静态派发(直接派发)、函数表派发、消息派发
swift派发机制总结:
Swift中所有ValueType(值类型:Struct、Enum)使用直接派发;
Swift中协议的Extensions使用直接派发,初始声明函数使用函数表派发;
Swift中Class中Extensions使用直接派发,初始声明函数使用函数表派发,dynamic修饰的函数使用消息派发;
Swift中NSObject的子类用@nonobjc或final修饰的函数使用直接派发,初始声明函数使用函数表派发,dynamic修饰的Extensions使用消息派发;
3)Swift中函数派发查看方式: 可将Swift代码转换为SIL(中间码)
swiftc -emit-silgen -O example.swift

10.什么是泛型?泛型是用来解决什么问题的?

泛型是用来使类型和算法安全的工作的一种类型。在 Swift 中,在函数和数据结构中都可以使用泛型,例如类、结构体和枚举。
泛型一般是用来解决代码复用的问题。常见的一种情况是,你有一个函数,它带有一个参数,参数类型是 A,然而当参数类型改变成B的时候,你不得不复制这个函数。

11.Swift常用关键字

1、class

在Swift当中, 我们使用Class关键字去声明一个类和声明类方法

2、let

Swift里用let修饰的变量会是一个不可变的常量,即我们不可以对它进行修改

3、var

Swift中用var修饰的变量是一个可变的变量,即可以对它进行修改

4、struct

在Swift中, 我们使用struct关键字去声明结构体

5、enum

在Swift中, 我们使用enum关键字去声明枚举

6、final

Swift中,final关键字可以在class、func和var前修饰。表示 不可重写 可以将类或者类中的部分实现保护起来,从而避免子类破坏

7、override

在Swift中, 如果我们要重写某个方法, 或者某个属性的话, 我们需要在重写的变量前增加一个override关键字

8、subscript

在Swft中,subscript关键字表示下标,可以让class、struct、以及enum使用下标访问内部的值

9、static

Swift中,用static关键字声明静态变量或者函数,它保证在对应的作用域当中只有一份, 同时也不需要依赖实例化

10、mutating

Swift中,mutating关键字指的是可变即可修改。用在structure和enumeration中,虽然结构体和枚举可以定义自己的方法,但是默认情况下,实例方法中是不可以修改值类型的属性。为了能够在实例方法中修改属性值,可以在方法定义前添加关键字mutating

11、typealias

在Swift中,使用关键字typealias定义类型别名(typealias就相当于objective-c中的typedef),就是将类型重命名,看起来更加语义化

12、lazy

在Swift中,lazy关键修饰的变量, 只有在第一次被调用的时候才会去初始化值(即懒加载)

13、init

在Swift 中,init关键字也表示构造器

14、required

在Swift里,required是用来修饰init方法的,说明该构造方法是必须实现的

15、extension

在swift中,extension与Objective-C的category有点类似,但是extension比起category来说更加强大和灵活,它不仅可以扩展某种类型或结构体的方法,同时它还可以与protocol等结合使用,编写出更加灵活和强大的代码。它可以为特定的class, strut, enum或者protocol添加新的特性。当你没有权限对源代码进行改造的时候,此时可以通过extension来对类型进行扩展

16、convenient

swift中,使用convenience修饰的构造函数叫做便利构造函数 。便利构造函数通常用在对系统的类进行构造函数的扩充时使用

17、deinit

在Swift中,deinit属于析构函数,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。和OC中的dealloc 一样的

18、fallthrough

swift语言特性switch语句的break可以忽略不写,满足条件时直接跳出循环.fallthrough的作用就是执行完当前case,继续执行下面的case.类似于其它语言中省去break里,会继续往后一个case跑,直到碰到break或default才完成的效果

19、protocol

在Swift中,protocol关键字也是属于协议

20、open

在Swift中,open修饰的对象表示可以被任何人使用,包括override和继承

21、public

在Swift中,public表示公有访问权限,类或者类的公有属性或者公有方法可以从文件或者模块的任何地方进行访问

22、internal

在Swift中,public表示内部的访问权限。即有着internal访问权限的属性和方法说明在模块内部可以访问,超出模块内部就不可被访问了。在Swift中默认就是internal的访问权限。

23、private

在Swift中,private私有访问权限。被private修饰的类或者类的属性或方法可以在同一个物理文件中访问。如果超出该物理文件,那么有着private访问权限的属性和方法就不能被访问

24、fileprivate

在Swift中,fileprivate访问级别所修饰的属性或者方法在当前的Swift源文件里可以访问

说明:5种修饰符访问权限排序open> public > interal > fileprivate > private。

12.指定构造器和便利构造器有什么区别?

类必须要有一个指定构造器,可以没有便利构造器
便利构造器必须调用本类另一个构造器,最终调用到本类的指定构造器
便利构造器前面需要添加convenience关键字

13.Swift中的访问控制权限?

Open:实体可被同一模块内所有实体访问,模块外可导入该模块即可访问,模块外可被继承和重写。
Public:实体可被同一模块内所有实体访问,模块外可导入该模块即可访问,模块外不能被继承和重写。
Internal:实体可被同一模块内所有实体访问,模块外无法访问,大部分实体默认是Internal级别。
fileprivate:限制实体只能在当前文件内访问到,不管是否在本类的作用域。
private: 限制实体只能在本类的作用域且在当前文件内能访问。

14.try try? try! 的区别

try 出现异常处理异常
try? 不处理异常,返回一个可选值类型,出现异常返回nil
try! 不让异常继续传播,一旦出现异常程序停止,类似NSAssert()

15.计算属性与存储属性

存储属性就是存储在特定类、结构体里的一个常量或者变量。
可以在定义存储属性的时候指定默认值。
可以在构造过程中设置或者修改存储属性的值。

枚举、类、结构体除了拥有存储属性,还可以定义计算属性。
计算属性不直接存储值,而是提供一个getter和一个可选的setter来间接获取、设置其他属性和变量的值

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 227,488评论 6 531
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 98,034评论 3 414
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 175,327评论 0 373
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 62,554评论 1 307
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,337评论 6 404
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 54,883评论 1 321
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,975评论 3 439
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,114评论 0 286
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,625评论 1 332
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,555评论 3 354
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,737评论 1 369
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,244评论 5 355
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,973评论 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,362评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,615评论 1 280
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,343评论 3 390
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,699评论 2 370

推荐阅读更多精彩内容

  • 无论是对于公司还是开发者或设计师个人而言,面试都是一项耗时耗钱的项目,本文作者Cameron Banga从编程、设...
    cuagain阅读 1,377评论 0 2
  • 整理的一些iOS面试相关问题,持续更新,敬请关注 如果您觉得里面的问题不错,值得在面试准备的时候学习看看,之前看了...
    iOS弗森科阅读 3,684评论 0 16
  • 之前看了很多面试题,感觉要不是不够就是过于冗余,于是我将网上的一些面试题进行了删减和重排,现在分享给大家。(题...
    Job_Yang阅读 12,107评论 12 143
  • 注:此文章来源:Job_Yang 的简书 1. Object-c的类可以多重继承么?可以实现多个接口么?Categ...
    广益散人阅读 1,355评论 0 13
  • 声明:面试是对自我审视的一种过程,面试题和iOS程序员本身技术水平没有对等关联,无论你能否全部答出,都不要对自己产...
    Kevin_wzx阅读 2,188评论 1 2