iOS面试题 - 总会有你需要的(二)

Runtime

1. objc在向一个对象发送消息时,发生了什么?
2. 什么时候会报unrecognized selector错误?iOS有哪些机制来避免走到这一步?
3. 能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?
4. runtime如何实现weak变量的自动置nil?
5. 给类添加一个属性后,在类结构体里哪些元素会发生变化?

RunLoop

1. runloop是来做什么的?runloop和线程有什么关系?主线程默认开启了runloop么?子线程呢?
2. runloop的mode是用来做什么的?有几种mode?
3. 为什么把NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主运行循环以后,滑动scrollview的时候NSTimer却不动了?
4. 苹果是如何实现Autorelease Pool的?

类结构

1. isa指针?(对象的isa,类对象的isa,元类的isa都要说)
2. 类方法和实例方法有什么区别?
3. 介绍一下分类,能用分类做什么?内部是如何实现的?它为什么会覆盖掉原来的方法?
4. 运行时能增加成员变量么?能增加属性么?如果能,如何增加?如果不能,为什么?
5. objc中向一个nil对象发送消息将会发生什么?(返回值是对象,是标量,结构体)

高级

1. UITableview的优化方法(缓存高度,异步绘制,减少层级,hide,避免离屏渲染)
2. 有没有用过运行时,用它都能做什么?(交换方法,创建类,给新创建的类增加方法,改变isa指针)
3. 看过哪些第三方框架的源码?都是如何实现的?(如果没有,问一下多图下载的设计)
4. SDWebImage的缓存策略?
5. AFN为什么添加一条常驻线程?
6. KVO的使用?实现原理?(为什么要创建子类来实现)
7. KVC的使用?实现原理?(KVC拿到key以后,是如何赋值的?知不知道集合操作符,能不能访问私有属性,能不能直接访问_ivar)

项目

1. 有已经上线的项目么?
2. 项目里哪个部分是你完成的?(找一个亮点问一下如何实现的)
3. 开发过程中遇到过什么困难,是如何解决的?

学习

1. 遇到一个问题完全不能理解的时候,是如何帮助自己理解的?举个例子?
2. 有看书的习惯么?最近看的一本是什么书?有什么心得?
3. 有没有使用一些笔记软件?会在多平台同步以及多渠道采集么?(如果没有,问一下是如何复习知识的)
4. 有没有使用清单类,日历类的软件?(如果没有,问一下是如何安排,计划任务的)
5. 平常看博客么?有没有自己写过?(如果写,有哪些收获?如果没有写,问一下不写的原因)

答案区

Runtime

1. objc在向一个对象发送消息时,发生了什么?
这片文章讲的比较详细-> 理解Objective-C中的消息发送

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

是该object中没有定义这个函数或者该对象也就被释放的时候就会报unrecognized selector错误

怎样避免

1.使用[id respondsToSelector:]进行判断
2.Method resolution
objc运行时会调用+resolveInstanceMethod:或者 +resolveClassMethod:,让你有机会提供一个函数实现。如果你添加了函数,那运行时系统就会重新启动一次消息发送的过程,否则 ,运行时就会移到下一步,消息转发(Message Forwarding)。
返回Nil和self,去调用第三步methodSignatureForSelector和forwarInvocation;返回receiver,如果receiver有响应就直接处理,如果没有就去对应的对象内去调用第三步;调用子类的函数,子类没有进行这几个方法的重载,在父类处理时返回子类,会死循环。
3.Fast forwarding
如果目标对象实现了-forwardingTargetForSelector:,Runtime 这时就会调用这个方法,给你把这个消息转发给其他对象的机会。 只要这个方法返回的不是nil和self,整个消息发送的过程就会被重启,当然发送的对象会变成你返回的那个对象。否则,就会继续Normal Fowarding。 这里叫Fast,只是为了区别下一步的转发机制。因为这一步不会创建任何新的对象,但下一步转发会创建一个NSInvocation对象,所以相对更快点。
4.Normal forwarding
这一步是Runtime最后一次给你挽救的机会。首先它会发送-methodSignatureForSelector:消息获得函数的参数和返回值类型。如果-methodSignatureForSelector:返回nil,Runtime则会发出-doesNotRecognizeSelector:消息,程序这时也就挂掉了。如果返回了一个函数签名,Runtime就会创建一个NSInvocation对象并发送-forwardInvocation:消息给目标对象。

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

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

原因如下:

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

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

4. runtime如何实现weak变量的自动置nil?
一个普遍的解释是:runtime对注册的类会进行布局,对于weak修饰的对象会放入一个hash表中。用weak指向的对象内存地址作为key,当此对象的引用计数为0的时候会dealloc,假如weak指向的对象内存地址是a,那么就会以a为键在这个weak表中搜索,找到所有以a为键的weak对象,从而设置为nil。

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

RunLoop

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

Run Loop是一让线程能随时处理事件但不退出的机制。RunLoop 实际上是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行Event Loop 的逻辑。线程执行了这个函数后,就会一直处于这个函数内部 “接受消息->等待->处理” 的循环中,直到这个循环结束(比如传入 quit 的消息),函数返回。让线程在没有处理消息时休眠以避免资源占用、在有消息到来时立刻被唤醒。

主线程的RunLoop是自动创建并启动

子线程的RunLoop需要手动创建

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

用来控制一些特殊操作只能在指定模式下运行,一般可以通过指定操作的运行mode 来控制执行时机,以提高用户体验

系统默认注册了5个Mode:
(1)kCFRunLoopDefaultMode: App的默认 Mode,通常主线程是在这个 Mode 下运行的。
(2)UITrackingRunLoopMode: 界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响。
(3)UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用。
(4)GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到。
(5)kCFRunLoopCommonModes: 这是一个占位的 Mode,没有实际作用。

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

ScrollView滚动过程中会因为mode的切换,而导致NSTimer将不再被调度。当我们滚动的时候,也希望不调度,那就应该使用默认模式。但是,如果希望在滚动时,定时器也要回调,那就应该使用common mode。

4. 苹果是如何实现Autorelease Pool的?

详情查看此篇文章->黑幕背后的Autorelease

类结构

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

isa指针是一个Class 类型的指针. 每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass).根元类的isa指针指向本身,这样形成了一个封闭的内循环。

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

Objective-C里面既有实例方法也类方法。类方法(Class Method) 有时被称为工厂方法(Factory Method)或者方便方法(Convenience method)。工厂方法的称谓明显和一般意义上的工厂方法不同,从本质上来说,类方法可以独立于对象而执行,所以在其他的语言里面类方法有的时候被称为静态方法。
注意点一:类方法
1,类方法可以调用类方法。
2,类方法不可以调用实例方法,但是类方法可以通过创建对象来访问实例方法。
3,类方法不可以使用实例变量。类方法可以使用self,因为self不是实例变量。4,类方法作为消息,可以被发送到类或者对象里面去(实际上,就是可以通过类或者对象调用类方法的意思)。
注意点二:self的规则大家需要记住下面的规则:
1,实例方法里面的self,是对象的首地址。
2,类方法里面的self,是Class.尽管在同一个类里面的使用self,但是self却有着不同的解读。在类方法里面的self,可以翻译成class self;在实例方法里面的self,应该被翻译成为object self。在类方法里面的self和实例方法里面的self有着本质上的不同,尽管他们的名字都叫self。

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

作用:可以在不修改原来类的基础上,为一个类扩展方法。

iOS分类底层实现原理小记

CocoaFramework有很多是用Category实现的,重写之后,会导致在Runtime的时候,只有一个方法会被执行,而哪个会被执行是undefined。

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

看这个解释-> 能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?

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

在 Objective-C 中向 nil 发送消息是完全有效的——只是在运行时不会有任何作用
详情看此篇文章->问题[※※]:objc中向一个nil对象发送消息将会发生什么?

高级

1. UITableview的优化方法(缓存高度,异步绘制,减少层级,hide,避免离屏渲染)
优化的方式就那几种,百度一搜一大把,下面这个文章说的比较全面了 参考此篇文章即可-> iOS中UITableView性能优化

2. 有没有用过运行时,用它都能做什么?(交换方法,创建类,给新创建的类增加方法,改变isa指针)
这个同上百度一大把 为了方便推荐个链接吧->iOS~runtime理解

3. 看过哪些第三方框架的源码?都是如何实现的?(如果没有,问一下多图下载的设计)
比较好的第三方源码个人推荐YYKit
然后多图下载的话参考这篇文章->iOS开发网络多线程之多图下载
然后比较好的第三方如SDWebImage、YYWebImage都支持多图下载

4. SDWebImage的缓存策略?

1.缓存策略-SDWebImageOptions
默认是开启了硬盘\内存缓存的

  • SDWebImageRetryFailed 下载失败了会再次尝试下载
  • SDWebImageLowPriority 当UIScrollView等正在滚动时,延迟下载图片(放置scrollView滚动卡)
  • SDWebImageCacheMemoryOnly 只缓存到内存中,不缓存到硬盘上
  • SDWebImageProgressiveDownload 图片会一点一点慢慢显示出来(就像浏览器显示网页上的图片一样)
  • SDWebImageRefreshCached 将硬盘缓存交给系统自带的NSURLCache去处理,当同一个URL对应的图片经常更改时可以用这种策略

5. AFN为什么添加一条常驻线程?
正常的线程任务完成后,线程就为finished状态,只能销毁再创建。如果想让一个线程常驻线程,实时的响应调度,则可以利用runloop高效的分配任务。

- (void)viewDidLoad {
    [super viewDidLoad];

    //创建一个线程
    self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(createRunloopByNormal) object:nil] ;
//
//    self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(createRunloopByCFObserver) object:nil] ;
//
//    self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(createRunloopByCFTimer) object:nil] ;
//
//    self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(createRunloopByCFSource) object:nil] ;


    [self.thread start];
}
/**
 *  一般创建runloop的方法。结果:成功
 */
- (void)createRunloopByNormal{
    @autoreleasepool {

        //添加port源,保证runloop正常轮询,不会创建后直接退出。
        [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];

        //开启runloop
        [[NSRunLoop currentRunLoop] run];
    }
}

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

当观察某对象A时,KVO机制动态创建一个对象A当前类的子类,并为这个新的子类重写了被观察属性keyPath的setter 方法。setter 方法随后负责通知观察对象属性的改变状况。
KVO 的实现依赖于 Objective-C 强大的 Runtime
来来来 看这里->iOS开发-- KVO的实现原理与具体应用

7. KVC的使用?实现原理?(KVC拿到key以后,是如何赋值的?知不知道集合操作符,能不能访问私有属性,能不能直接访问_ivar)
这里面解释的很清楚 看这里就行->iOS底层-KVC使用实践以及实现原理

项目

1. 有已经上线的项目么?
这个就不说了 如果没有上线的项目的话那还面试个卵

2. 项目里哪个部分是你完成的?(找一个亮点问一下如何实现的)
这个看自己实际情况 。
我本人呢 已经独立完成过很多个项目 差不多80%的已经上架到AppStore 有些个别的是公司内部使用的

3. 开发过程中遇到过什么困难,是如何解决的?
困难是遇到过很多 一些不好解决的坑都踩过 怎么解决的么 技术的扎实是一方面 还有就是多动脑 要从多个方面想解决办法 然后还有就是沉下心来慢慢想办法 不要难倒了几分钟就烦躁 这样解决不了问题的

学习

1. 遇到一个问题完全不能理解的时候,是如何帮助自己理解的?举个例子?
举个栗子
这个说明你遇到的问题已经超出你知识的领域 所以也不要靠你自己原本的知识去理解他 这时就要找解决办法了,百度一下或者谷歌一下,如果有大牛的话 最好问问他们 详细的讲解一下 这样比自己慢慢理解要来的快得多

2. 有看书的习惯么?最近看的一本是什么书?有什么心得?
问:最近在看什么书?
答:(哈哈哈~)

3. 有没有使用一些笔记软件?会在多平台同步以及多渠道采集么?(如果没有,问一下是如何复习知识的)
这个的话我个人也尝试用过很多笔记软件 但是都差一点感觉 不知道是画风问题还是软件的名字问题 但是我一直坚持使用的是系统自带的备忘录 就是简单方便 没有别的原因

4. 有没有使用清单类,日历类的软件?(如果没有,问一下是如何安排,计划任务的)

这个安排计划和任务也是用的备忘录

5. 平常看博客么?有没有自己写过?(如果写,有哪些收获?如果没有写,问一下不写的原因)
平时看博客 也看各类开发者网站 平时就提高自己技术的宽度和深度
写的话还是在上写得多 比较喜欢的风格

总结

写这篇文章呢 是我有一次在我关注的微信公众号里看到的一篇文章 里面的内容就是这里列的所有的问题 后来我才发现这个面试题在网上很早就有了 但是感觉全是题目没有一个人整理过答案 我一想 这些题目对于正在或者即将想面试的ios开发者们有很大的帮助 也对自己是一个复习和学习的过程 这里面有一些问题的答案我是借鉴或转载了前辈们的知识结晶 在这里我统一声明一下 就不一一的艾特了 如果有冒犯 请多多原谅。

你可能感兴趣的:(iOS面试题 - 总会有你需要的(二))