iOS面试题总结
-
什么是Block?
Block是将函数及其执行上下文封装起来的对象。 -
什么是Block调用?
Block调用实质上就是函数调用。 -
截获变量
- 对基本数据类型的局部变量截获其值。
- 对象类型的局部变量连同所有权修饰符一起截获。
- 局部静态变量以指针形式截获。
- 全局变量、静态全局变量不截获。
-
__block修饰符
一般情况下,对被截获变量进行赋值操作需要添加__block修饰符。- 需要__block:局部变量:基本数据类型、对象类型
- 不需要__block:静态局部变量、全局变量、静态局部变量。
赋值 不等于 使用!
__block 修饰的变量变成了对象。
-
__forwarding存在的意义:
不论在任何内存位置,都可以顺利的访问同一个__block变量。 -
为什么block会产生的循环引用?
- 当前block对当前对象的某一成员变量截获的话,block会对这一变量有一个强引用,而当前对象又对其当前block有强引用,就产生了一个自循环引用。可以通过__weak对该成员变量进行修饰来消除循环引用。
- 使用__block来修饰,在MRC下不会循环引用,在ARC下会循环引用,在ARC下要通过断环的方式解除循环引用,但是有个弊端,如果block一直没有调用,这个循环引用是没有办法解除的。
-
runtime
- 数据结构
- objc_object
- objc_class
- isa指针:对象指向类对象,类对象指向元类对象。
- method_t
- 类对象与元类对象
类对象:存储实例方法列表等信息。
元类对手:存储类方法列表等信息。 - 消息传递的机制:
- 缓存是否命中:
hash查找 - 当前类方法列表是否命中
- 已排序好的列表:二分查找
- 没有排序的列表:一般遍历
- 逐级父类方法列表是否命中:
superClass逐级查找到1步骤开始。 - 转到消息转发
- 缓存是否命中:
- 方法缓存
- 消息转发
- Method-Swizzling
- 动态添加方法:class_addMethod(self, @selector(test), testImp, "v@:");
- 动态方法解析:
- @dynamic:
- 动态运行时语言将函数决议推迟到运行时。
- 编译时语言在编译期进行函数决议。
- @dynamic:
- 数据结构
-
能否向编译后的类中增加实例变量?
不能。 -
能否向动态添加的类中增加实例变量?
可以,调用注册的一对方法 -
多线程
- GCD:
- 同步dispatch_sync/异步dispatch_asyn 和 串行seri/并发concurrent
- 同步串行:同步在当前线程执行。串行为主队列会死锁:队列引起的循环等待。非主队列,不会死锁。
- dispatch_barrier_async:异步栅栏函数:解决多读单写
- dispatch_group:create、enter、notify
- 同步dispatch_sync/异步dispatch_asyn 和 串行seri/并发concurrent
怎样用GCD实现多读单写?
就是利用dispatch_barrier_async实现。-
NSOperation:AFNetworking、图片异步下载:
-
添加任务依赖
-
控制任务执行状态控制:isReady、isExecuting、isFinished、isCancelled:
- 只重写main方法,底层控制 变更任务执行完成状态以及任务退出。
- 重写了start方法,自行控制 任务状态。
(系统是怎么移除一个isFinished=YES的NSOperation的?
通过KVO。) -
控制最大并发量
-
-
NSThread:常驻线程
- start()
- pthread_creare
- main()
- [_target perfirmSelector:_selector withObject:_arg]
- _selector维护runloop事件循环,达到常驻线程。
- exit()
-
多线程与锁:线程间同步、资源共享。
iOS当中都有哪些锁:- @synchronized:一般在创建单例对象的时候使用,来保证在多线程环境下被创建的对象是唯一的。
- atomic:
- 修饰属性的关键字
- 对被修饰对象进行原子操作,即赋值时可以保证安全,但不负责使用。
- OSSpinLock:自旋锁:循环等待询问,不释放当前资源。用于轻量级数据访问,比如简单的int值 +1/-1操作。
- NSRecursiveLock:递归锁:可以重入,可以解决NSLoc重入导致的死锁。
- NSLock:解决线程同步问题,来保证各个线程互斥进入自己的临界区。
- dispatch_semaphore_t:信号量:create、wait、signal:调用信号量阻塞是一个主动行为。唤醒是一个被动行为。
- GCD:
-
iOS系统为我们提供的几种多线程技术,各自的特点是怎样的?
主要提供了三种多线程技术,分别为GCD、NSOperation和NSOperationQueue、NSThread。GCD用来实现一些简单的线程同步、子线程的分派、多读单写的解决。NSOperation像AFNetworking、SDWebImageView,方便对任务的状态进行控制,以及添加、移除依赖。NSThread实现常驻线程。 -
什么是RunLoop?
RunLoop是通过内部维护的事件循环来对事件/消息 进行管理的一个对象。 -
事件循环是什么?
- 没有消息需要处理时,休眠以避免资源暂用。
用户态 -> 内核态 - 有消息要处理时,立刻被唤醒。
用户态 <- 内核态
维护的事件循环可以不断地用来处理消息,进行管理,同时没有消息.....
- 没有消息需要处理时,休眠以避免资源暂用。
-
RunLoop数据结构:
NSRunLoop是CFRunLoop的封装,提供了面向对象的API。- CFRunLoop:
- pthread(一一对应:RunLoop和线程的关系)
- currentMode:CFRunLoopMode
- modes:NSMutabbleSet<CFRunLoopMode *>
- coommonModes:NSMutabbleSet<NSString *>
- commonModeItems
- CFRunLoopMode:
- name:NSDefaultRunLoopMode、...
- sources0:需要手动唤醒线程。
- sources1:具备唤醒线程的能力。
- observers:
观测时间点:kCFRunLoopEntry、beforeTimers、beforeSources、beforeWaiting、afterWaiting、Exit。 - timers
- Source/Timer/Observer
- CFRunLoop:
-
CommonMode的特殊性?
NSRunLoopCommonModes:- CommonMode不是实际存在的一种Mode。
- 是同步Source/Timer/Observer到多个Mode中的一种技术方案。
-
RunLoop与多线程的关系?
- 线程和RunLoop是一一对应的。
- 自己创建的线程默认是没有RunLoop的。
-
怎样实现一个常驻线程?
- 为当前线程开启一个RunLoop。
- 向该RunLoop中添加一个Port/Source等维持RunLoop的事件循环。
- 启动该RunLoop。
-
怎么保证子线程数据回来更新UI的时候不打断用户的滑动操作?
因为用户的滑动操作时,RunLoop是TraikingMode,所以可以通过子线程抛回给主线程进行UI更新的这一块逻辑包装起来,提交到主线程的RunLoop的DefaultMode下,当停止滑动后,RunLoop切换回DefaultMode下,这个时候会处理刚才子线程抛回给主线程DefaultMode下的任务。这样是不会打断用户的滑动操作。 -
HTTP中的GET和POST方式有什么区别?
- GET:米等的、可缓存的、不安全的。
- POST:不密等的、不可缓存。
-
HTTPS连接建立流程是什么?
- 客户端发送给服务端一个支持的加密算法列表、TRL版本好,随机数c。
- 服务端回给客户端一个证书、商定的加密算法。
- 首先通过非对称加密进行对称加密的秘钥的传输。
- 通过对非对称加密所保护的对称秘钥进行后续的网络访问。
-
TCP和UDP有什么区别?
- TCP是面向连接的、支持可靠传输、面向字节流、提供流量的控制、提供拥塞的控制。
- UDP是无连接的,只是简单的提供复用、分用以及差错检查的基本的传输层的功能。
-
客户端怎样避免DNS劫持?
- HTTPDNS
- 长连接