iOS面试题库

面试题目

2017-06-08  本文已影响87人  奋斗的蝼蚁

1、基础篇

1、1   属性和成员变量的区别 ?

1、11 涉及到的问题是类的分类中是否可以添加属性。

肯定是可以添加的。如果有面试经验的人肯定会被问到 是否可以添加属性和成员变量,这里要注意的是成员变量和属性是有区别的(属性是有set 和get 方法 ,成员变量是没有的,属性是可以用点语法调动的,但是成员变量是使用self-> 来使用)。那是否可以动态添加成员变量呢,答案是不可以的。因为Category 是运行期决定的,不是编译期的决定的,所以category是无法添加实例变量的(因为在运行期,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局,这对编译型语言来说是灾难性的)。那是否不可以添加方法了 ,答案是可以添加方法,因为Category 有一个添加方法的数组(什么?这个百度去吧)。

1、12 能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么

不能向编译后得到的类中增加实例变量;能向运行时创建的类中添加实例变量;

解释下:

因为编译后的类已经注册在 runtime 中,类结构体中的objc_ivar_list实例变量的链表 和instance_size实例变量的内存大小已经确定,同时runtime 会调用class_setIvarLayout或class_setWeakIvarLayout来处理 strong weak 引用。所以不能向存在的类中添加实例变量;

运行时创建的类是可以添加实例变量,调用class_addIvar函数。但是得在调用objc_allocateClassPair之后,objc_registerClassPair之前,原因同上

1、12内存管理语义

assign : 只会执行针对 “纯量类型”(CGFloat、NSInteger)等。

strong : 拥有关系,设置新值时,设置方法会先保留新值,并释放旧值,然后在添加新值设置上去。  

weak :非拥有关系,设置新值,不保留新值,也不释放旧值,和assign类似,但是所指的对象遭到摧毁时,属性值也会清空。

copy: 不保留新值,而是将其拷贝,当属性类型为NSStringn*时,经常用此特质来保护期封装性。NSMutableString 是NSString 的子类,可以修改值。

copy:涉及到内容复制和地址复制。copy 涉及到问题 ,先给出答案,

[immutableObject copy] // 浅复制

[immutableObject mutableCopy] //深复制

[mutableObject copy] //深复制

[mutableObject mutableCopy] //深复制 

这里所说的复制是指,指针的地址复制,不是指针所指向的对象的地址复制。举个例子

NSArray *array2 = @[ @1, @2, @3, @4 ];

NSLog(@"array2===%p==",&array2);  (指针所指向对象的值)

NSLog(@"array2===%p==",array2); (指针的值)

如果在多层数组中,对第一层进行内容拷贝,其它层进行指针拷贝,这种情况是属于深复制,还是浅复制? 这个是 集合的单层深复制

1、3 IMP 和SEL 的区别

SEL : 类成员方法的指针,但不同于C语言中的函数指针,函数指针直接保存了方法的地址,但SEL只是方法编号。

IMP:一个函数指针,保存了方法的地址

编号SEL最后还是要通过Dispatch table表寻找到对应的IMP,IMP就是一个函数指针,然后执行这个方法

2、中级偏篇

2.1 objc_msgSend 传递消息

objc_msgSend 是传递消息,如果向某对象传递消息,那就会使用动态绑定机制来决定需要调用的方法。给对象发送消息可以这样来写:

id returnValue = [someObject messageName:parameter];

在本例中,someObject叫做 “接受者,messageName叫做 “选择子””,选择子和参数合起来称为“消息”。编译器看到此消息后,将其转换成一条标准的C语言函数调用,所调用的函数乃是消息传递机制中的核心函数,叫做 object_msgSend, 

void objc_msgSend(id self,SEL cmd, ...)

接收者所属的类中搜寻其“方法列表 (list of methods)” ,如果能找到与选择子名称相符的方法,就跳至其实现代码。若是找不到,那就沿着继承体系继续向上查找,等找到合适的方法之后再跳转。如果最终还是找不到相符的方法,那就执行“消息转发”的操作。

objc_msgSend 会将匹配结果缓存在 “快速映射表”里面,每个类都有这样一块缓存,若是稍后还向该类发送与选择子相同的消息,那么执行起来就很快了。

 2.2 消息转发(message forwarding)

在编译期向类发送了期无法解读的消息并不会报错,因为在运行期可以继续向类中添加方法,所以编译器在编译时还无法确定知道到底会不会有某个方法实现。当对象接收到无法解读的消息后,就会启动“消息转发”机制,程序员可经由此过程告诉对象应该如何处理未知消息。(unrecognized seletor sent to instance) 这个是平常开发中遇到的一个问题,方法识别不了,

消息转发分为两大阶段:第一阶段先征询接收者,所属的类,看其是否能动态添加方法,以处理当期这个 “未知的选择子”,这叫做“动态方法解析”。第二阶段涉及“完整的消息转发机制”,第一阶段执行完说明,接收对象无法动态添加方法。此时,运行期系统会请求接收者以其他手段来处理与消息相关的方法调用。这又细分两小步。首先,请接收者看看有没有其他对象来处理这条消息,如果有,把这条消息转给那个对象,于是消息转发过程结束,一切如常。如果没有备援的接收者,则启动完成的消息转发机制,运行期系统会把与消息有关的全部细节都封装到NSInvocation 对象中,再给接收者最后一次机会,让接收者设法解决当前还未处理的这条消息。 找一张网上的图片。

问题 :每个类中都有一个方法列表?

2.3 Block

2.31 block的实质是什么?一共有几种block?都是什么情况下生成的?

block 就是一种代替函数指针的语法结构,原来使用函数指针时,需要用“不透明的void指针”来传递状态,block 一共有三种:全局块,堆块,栈块,

2.32 为什么在默认情况下无法修改被block捕获的变量? __block都做了什么?

没有加__block ,是传值 ,加了__block 是传地址。详情看这个(http://www.cnblogs.com/HypeCheng/p/4597205.html)。

2.33 模拟一下循环引用的一个情况?block实现界面反向传值如何实现?

2.34 block 为什么需要添加copy?

没有添加copy block是在栈,添加了copy 是复制到堆区,栈是在内存中是一块连续的存储空间,堆在内存中是分散的,是全局的,所以,使用范围就变大了。栈区是系统负责回收的,而堆区一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表,所以 如果不使用Copy,block 回收的时候,你都不知道。

2.35 SDWebImage 在tableView 中加载大量图片,如何保证加载后的图片是对应相应的URL,不会错位显示图片。

Runtime

objc在向一个对象发送消息时,发生了什么?

什么时候会报unrecognized selector错误?iOS有哪些机制来避免走到这一步?

能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?

runtime如何实现weak变量的自动置nil?

给类添加一个属性后,在类结构体里哪些元素会发生变化?

http://nshipster.cn/method-swizzling/

2.4 iOS下所有的本地持久化方?

三、RunLoop

3.1 runloop是来做什么的?runloop和线程有什么关系?主线程默认开启了runloop么?子线程呢?

run loop和线程是紧密相连的,可以这样说run loop是为了线程而生,没有线程,它就没有存在的必要, 主线程默认是开启了runloop的,子线程需要自己手动配置和开启。

runloop的mode是用来做什么的?有几种mode?

3.2 model 主要是用来指定事件在运行循环中的状态,NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默认,空闲状态UITrackingRunLoopMode:ScrollView滑动时

UIInitializationRunLoopMode:启动时NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合

苹果公开提供的 Mode 有两个:

NSDefaultRunLoopMode(kCFRunLoopDefaultMode)NSRunLoopCommonModes(kCFRunLoopCommonModes)

3.3 为什么把NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主运行循环以后,滑动scrollview的时候NSTimer却不动了?

model 由NSDefaultRunLoopMode 切换到UITrackingRunLoopMode的时候,NSTimer 就失效了,scrollview就生效了。

model 只能存在一种类型,换成 NSRunLoopCommonModes model 就可以。

苹果是如何实现Autorelease Pool的?

3.4 动画

1、隐式动画:

核心动画的隐式动画模型假定所有动画图层属性的变化应该是渐进的和异步的。动态的动画场景可以在没有显式的动画图层时候实现。改变动画显示的图层的属性将会导致图层隐式把旧值动画显示为新值,虽然动画是持续的,但是设置新的目标值会导致图层从当前状态动画过度到新的目标值

OrderSearchVC *search = [[OrderSearchVC alloc] init];    [self.navigationController pushViewController:search animated:YES];

2、显式动画:

核心动画同事提供了一个显示动画模型。该显式动画模型需要你创建一个动画对象,并设置开始值和结束的值,显示动画不会开始执行,直到你把该动画应用到某个图层上面

四、类结构

4.1 isa指针?(对象的isa,类对象的isa,元类的isa都要说)

对象isa :实例所属的类。

类对象的isa:类对象指针isa所指向的类型是另外一个雷,叫做“元类”,表述类对象本身所具备的元数据(类对象的实例方法)。

4.2 类方法和实例方法有什么区别?

4.3 介绍一下分类,能用分类做什么?内部是如何实现的?它为什么会覆盖掉原来的方法?

1)、category的方法没有“完全替换掉”原来类已经有的方法,也就是说如果category和原来类都有methodA,那么category附加完成之后,类的方法列表里会有两个methodA

2)、category的方法被放到了新方法列表的前面,而原来类的方法被放到了新方法列表的后面,这也就是我们平常所说的category的方法会“覆盖”掉原来类的同名方法,这是因为运行时在查找方法的时候是顺着方法列表的顺序查找的,它只要一找到对应名字的方法,就会罢休^_^,殊不知后面可能还有一样名字的方法

4.4 运行时能增加成员变量么?能增加属性么?如果能,如何增加?如果不能,为什么?

 这个问题和在分类中处于编译期间添加实例变量 和在运行时添加编译实例变量 有啥区别?????

4.5 objc中向一个nil对象发送消息将会发生什么?(返回值是对象,是标量,结构体)

4.6 GCD

4.61 你碰到过死锁的问题吗?

同步+主队列 会死锁

五、高级

5.1 UITableview的优化方法(缓存高度,异步绘制,减少层级,hide,避免离屏渲染)

5.2 有没有用过运行时,用它都能做什么?(交换方法,创建类,给新创建的类增加方法,改变isa指针)

5.3 看过哪些第三方框架的源码?都是如何实现的?(如果没有,问一下多图下载的设计)

5.4 SDWebImage的缓存策略?

内存和硬盘缓存策略。

5.4.1 SDWebImage 清除图片的策略是怎么样的。

5.5 AFN为什么添加一条常驻线程?

 为了线程保活

5.6 KVO的使用?实现原理?(为什么要创建子类来实现)

5.7 KVC的使用?实现原理?(KVC拿到key以后,是如何赋值的?知不知道集合操作符,能不能访问私有属性,能不能直接访问_ivar)

5.8 事件传递

http://www.jianshu.com/p/2e074db792ba 很详细。

5.8 initialize和load 的区别。

在加载阶段,如果类实现了load方法,系统就会调用,分类也可以定义此方法,类的load方法要比分类中的先调用。与其他方法不同,load方法不参与覆写机制,

initialize和load 都是只执行一次,但是load 是一定会调用的,initialize是类用到了才会调用类的initialize,load是应用程序必须阻塞并等着所有类的load都执行完,才能继续。

执行load方法时候,程序是阻塞状态,但是执行initialize的时候是正常状态。

load 不遵循继承关系,子类的load执行要等他的父类执行完之后才可以执行。

initialize 遵循继承关系。

5.9 日常中开发中你遇到的最多的Crash 是什么,你是怎么解决的。

数组、字典的Crash 就不要说了,这样显的你太low了,这个是个开放的问题,没有什么具体的答案,下面列举本人开发中遇到的Crash 文件。

5.91、EXC_BAD_ACCESS 野指针,最常见的原因是在初始化方法中初始化变量时用错了所有权修饰符,这会导致对象释放。

5.92、SIGSEGV 段错误信号是操作系统产生的一个更严重的问题。当硬件出现错误,访问不可读的内存地址或受保护的内存地址写入数据时,就会发生这个错误。

5.93  SIGBUG

5.94 SIGTRAP

5.95 EXC_ARITHMETIC

5.60 SIGILL

5.61 SIGABRT

6.0你项目中的日活和注册用户是多少。

 未完 慢慢更新,加班之后才尝试写文章

参考文献:

https://juejin.im/post/5938dfdb8d6d810058481572

https://github.com/ChenYilong/iOSInterviewQuestions

上一篇下一篇

猜你喜欢

热点阅读