iOS⾯试题汇总+答案
前⾔:
最近把 iOS ⾯试中可能会遇到的问题整理了⼀番, 题⽬⼤部分是⽹上收录的, ⽅便⾃⼰巩固复习, 也分享给⼤家; 希望对⼤家有所帮助!
对于答案,不⼀定都合适,欢迎⼤家积极讨论;整理不易,如果您觉得还不错,⿇烦在⽂末 “点个赞” ,或者留下您的评论“Mark” ⼀下,谢谢您的⽀持
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.利⽤消息转发机制解决⽅法找不到的异常问题
3.讲⼀下 OC 的消息机制
1.当向⼀个对象发送消息时,objc_msgSend ⽅法根据对象的 isa 指针找到对象的类,然后在类的调度表(dispatch table)中查找 lector。
2.如果⽆法找到 lector,objc_msgSend 通过指向⽗类的指针找到⽗类,并在⽗类的调度表(dispatch table)中查找 lector,以此类推直到 NSObject 类。干细胞读音
3.⼀旦查找到 lector,objc_msgSend ⽅法根据调度表的内存地址调⽤该实现。
4.通过这种⽅式,message 与⽅法的真正实现才在执⾏阶段进⾏绑定。自我保护手抄报
5.为了保证消息发送与执⾏的效率,系统会将全部 lector 和使⽤过的⽅法的内存地址缓存起来。
6.每个类都有⼀个独⽴的缓存,缓存包含有当前类⾃⼰的 lector 以及继承⾃⽗类的 lector。
7.查找调度表(dispatch table)前,消息发送系统⾸先检查 receiver 对象的缓存;缓存命中的情况下,消息发送(messaging)⽐直接调⽤⽅法(function call)只慢⼀点点。
油库管理4.动态绑定
1,在运⾏时确定要调⽤的⽅法,动态绑定将调⽤⽅法的确定也推迟到运⾏时。
2.在编译时,⽅法的调⽤并不和代码绑定在⼀起,只有在消实发送出来之后,才确定被调⽤的代码。
3.通过动态类型和动态绑定技术,您的代码每次执⾏都可以得到不同的结果。
4.运⾏时负责确定消息的接收者和被调⽤的⽅法;运⾏时的消息分发机制为动态绑定提供⽀持。
5.当您向⼀个动态类型确定了的对象发送消息时,运⾏环境系统会通过接收者的 isa 指针定位对象的类,并以此为起点确定被调⽤的⽅法,⽅法和消息是动态绑定的。⽽且,您不必在 Objective-C 代码中做任何⼯作,就可以⾃动获取动态绑定的好处。
6.您在每次发送消息时,特别是当消息的接收者是动态类型已经确定的对象时,动态绑定就会例⾏⽽透明地发⽣。
5月12日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_maphore_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.在m ain函数执⾏之前
1.1尽量删除⼀些不必要的系统⽂件和第三⽅库。
1.2尽量删除⼀些不必要的.h .m ⽂件。
1.3尽量不要在类的load函数放⼊⼤量初始化信息,这样会延迟加载时间。
2.d id f inis hlauch函数到第⼀个主界⾯加载显⽰阶段
2.1减少不必要的⽹络请求。
2.2较少不必要的数据初始化操作,尽量写成懒加载
2.3减少⼀些第三⽅sdk的初始化和版本检测相关代码
13.UIView 和 CA Layer 的区别?离我最近的夜市街
UIView 是 CA Layer 的 delegate,UIView 可以响应事件,⽽ CA Layer 则不能。
14.KVC 的主要应⽤的场景与注意的事项
KVC全称(key-Value coding)称呼为键值编码,在iOS开发中。允许开发者通过key名直接访问对象的属性,或者给对象的属性赋值。需要调⽤明确的存取⽅法,这样就可以在运⾏时动态访问和修改对象的属性,⽽不是在编译时确定。