iOS 笔记(实时更新)

1.关于Block

Block是将函数及其执行上下文封装起来的对象。
Block内部有isa指针,所以说本质也是OC对象。

关于Block变量截获

1.局部变量截获是值截获。
2.局部静态变量截获是指针截获。
3.全局变量,静态全局变量不截获,直接取值。

Block的几种形式

分为全局Block、栈Block、堆Block三种形式。
1.不使用外部变量的Block是全局Block。
2.使用外部变量并且未进行copy操作的是栈Block。
3.对栈Block进行copy操作的,就是堆Block,而对全局Block进行copy,仍是全局Block。
如果对栈Block进行copy,将会copy到堆区,对堆Block进行copy,将会增加引用计数,对全局Block进行copy,因为是已经初始化的,所以什么也不做。
另外由于block捕获的__block修饰的变量会去持有变量,那么如果用__block修饰self,且self持有block,并且block内部使用到__block修饰的self时,就会造成多循环引用,即self持有block,block 持有__block变量,而__block变量持有self,造成内存泄漏。
如果要解决这种循环引用,可以主动断开__block变量对self的持有,即在block内部使用完weakself后,将其置为nil,但这种方式有个问题,如果block一直不被调用,那么循环引用将一直存在。
所以,我们最好还是用__weak来修饰self。
具体参考:https://www.jianshu.com/p/0e1a0e7e988d

2.关于自动布局 Autolayout 优先级的使用

在Autolayout中每个约束都有一个优先级,优先级的范围是1~1000,默认创建的约束优先级为最高的1000
约束优先级核心就是为了如果存在多套约束的情况下,解决约束冲突。
关于固有的约束
有些控件能通过自己显示的内容计算出需要的Size,这个自动计算出来size就叫该控件的固有内容大小。这个大小是和需要显示的内容相关的。UIButton,UILabel就是具有固有内容大小属性的控件。UIButton可以根据它的title字符串长度和需要显示的image来计算需要的Size,UILabel可以根据它的text来计算。
Content Hugging Priority:该优先级表示一个控件抗被拉伸的优先级。优先级越高,越不容易被拉伸,默认是251。
Content Compression Resistance Priority:表示一个控件抗压缩的优先级,优先级越高,越不容易被压缩,默认是750。
具体参考:https://www.cnblogs.com/junhuawang/p/5691302.html

3.关于atomic和nonatomic

atomic只是保证了getter和setter存取方法的线程安全,并不能保证整个对象是线程安全的,因此在多线程编程时,线程安全还需要开发者自己来处理.
关于选择:atomic系统生成的getter、setter会保证get、set操作的安全性,但相对nonatomic来说,atomic要更耗费资源,且速度要慢,故在iPhone等小型设备上,如果没有多线程之间的通讯,使用nonatomic是更好的选择
具体参考:https://juejin.im/post/5a31dc76f265da430c11d3ab

4.关于响应者链

当事件发生的时候,响应链首先被发送给第一个响应者(往往是事件发生的视图,也就是用户触摸屏幕的地方)。事件将沿着响应者链一直向下传递,直到被接受并作出处理。一般来说,第一响应这是个视图对象或者其子类,当其被触摸后事件就交由它处理,如果他不处理,事件就会被传递给视图控制器对象UIViewController(如果存在),然后是它的父视图对象(superview),以此类推直到顶层视图。接下来会沿着顶层视图(topview)到窗口 (UIwindow 对象)再到程序的(UIApplication 对象),如果整个过程都没有响应这个事件,则该事件被丢弃,一般情况下,在响应链中只要有对象处理事件,事件就会被传递典型的响应路线图如:
First Responser -> The Window ->The Application->AppDelegate

5.关于UIView、UIWindow 和 CALayer

1.UIView:属于UIKit.framework框架,负责渲染矩形区域的内容,为矩形区域添加内容,响应区域的触摸事件,布局和管理一个或多个子视图。

2.UIWindow:属于UIKit.framework框架,是一种特殊的UIView,通常在一个程序中只有一个UIWindow,但可以手动创建多个UIWindow,同时加到程序里.UIWindow在程序中主要起到以下作用:
作为容器传递触摸消息到程序中的View和其他对象与UIViewController协同工作,方便完成设备方向旋转的支持。
作为容器,包含程序所有要显示的视图。
传递触摸消息到其他的UIView或其他对象。
与UIViewController协同工作,完成设备方向旋转的支持。

3.CAlayer:属于QuartzCore.famework,是用来绘制内容的,对内容进行动画处理依赖与UIView来显示,不能处理用户事件.UIView和CALayer是相互依赖的,UIView依赖CALayer提供内容,CALayer依赖UIView提供容器显示绘制内容。

延伸:UIViewController:每个视图控制器都有一个自带的视图,并且负责这个视图相关的一切事务,方便管理视图中的子视图,负责model和view的通信,检测设备旋转以及内存警告,是所有视图控制类的基类,定义了控制器的基本功能。

6.NSAutoreleasePool 是怎么工作的?

自动释放池以栈的形式实现:当你创建一个新的自动释放池时,它将被添加到栈顶。当一个对象收到发送 autorelease 消息时,它被添加到当前线程的处于栈顶的自动释放池中,当自动释放池被回收时,它们从栈中被删除, 并且会给池子里面所有的对象都会做一次 release 操作。

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

什么情况使用 weak 关键字?

在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如: delegate、block。
自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性一般也使用 weak,使用 storyboard(xib 不行)创建的 vc,会有一个叫 _topLevelObjectsToKeepAliveFromStoryboard 的私有数组强引用所有 top level 的对象,所以这时即便 outlet 声明成 weak 也没关系。当然,也可以使用 strong。

weak 和 assign 的不同点:

weak、assign 修饰的属性指向一个对象时都不会增加对象的引用计数。然而在所指的对象被释放时,weak 属性值会被置为 nil,而 assign 属性不会。
assign 可以用非 OC 对象以及基本类型,而 weak 必须用于 OC 对象。

8.runtime 如何实现 weak 属性?

weak 此特质表明该属性定义了一种「非拥有关系」(nonowning relationship)。为这种属性设置新值时,设置方法既不持有新值(新指向的对象),也不释放旧值(原来指向的对象)。

runtime 对注册的类,会进行内存布局,从一个粗粒度的概念上来讲,这时候会有一个 hash 表,这是一个全局表,表中是用 weak 指向的对象内存地址作为 key,用所有指向该对象的 weak 指针表作为 value。当此对象的引用计数为 0 的时候会 dealloc,假如该对象内存地址是 a,那么就会以 a 为 key,在这个 weak 表中搜索,找到所有以 a 为键的 weak 对象,从而设置为 nil。

runtime 如何实现 weak 属性具体流程大致分为 3 步:

1、初始化时:runtime 会调用 objc_initWeak 函数,初始化一个新的 weak 指针指向对象的地址。
2、添加引用时:objc_initWeak 函数会调用 objc_storeWeak() 函数,objc_storeWeak() 的作用是更新指针指向(指针可能原来指向着其他对象,这时候需要将该 weak 指针与旧对象解除绑定,会调用到 weak_unregister_no_lock),如果指针指向的新对象非空,则创建对应的弱引用表,将 weak 指针与新对象进行绑定,会调用到 weak_register_no_lock。在这个过程中,为了防止多线程中竞争冲突,会有一些锁的操作。
3、释放时:调用 clearDeallocating 函数,clearDeallocating 函数首先根据对象地址获取所有 weak 指针地址的数组,然后遍历这个数组把其中的数据设为 nil,最后把这个 entry 从 weak 表中删除,最后清理对象的记录。

9.category 和 extension 有什么区别?category 是如何加载的?category 的方法覆盖是怎么处理的?

具体参考:https://www.jianshu.com/p/40e28c9f9da5

9.使用runtime Associate方法关联的对象,需要在主对象dealloc的时候释放么?

无论在MRC下还是ARC下均不需要,被关联的对象在生命周期内要比对象本身释放的晚很多,它们会在被 NSObject -dealloc 调用的object_dispose()方法中释放。
具体参考:https://www.jianshu.com/p/c1b4841969e1

10.class_copyIvarList与class_copyPropertyList的区别

1.class_copyIvarList:能够获取.h和.m中的所有属性以及大括号中声明的变量,获取的属性名称有下划线(大括号中的除外)。
2.class_copyPropertyList:只能获取由property声明的属性,包括.m中的,获取的属性名称不带下划线。

11.class_ro_t 和 class_rw_t 的区别

细看两个结构体的成员变量会发现很多相同的地方,他们都存放着当前类的属性、实例变量、方法、协议等等。区别在于:class_ro_t存放的是编译期间就确定的;而class_rw_t是在runtime时才确定,它会先将class_ro_t的内容拷贝过去,然后再将当前类的分类的这些属性、方法等拷贝到其中。所以可以说class_rw_t是class_ro_t的超集,当然实际访问类的方法、属性等也都是访问的class_rw_t中的内容。
具体参考:https://www.jianshu.com/p/823eaedb3697

12.+load方法、+initialize方法以及分类中同名方法的调用顺序

1.+load方法的调用在main()函数之前,并且不需要主动调用,程序启动会主动加载。
主类和分类都会加载+load方法。
加载顺序:主类优先于分类加载,无关编译顺序。
分类间的加载顺序取决于编译顺序:编译在前则先加载,编译在后则后加载。
规则是父类由于子类,子类优于分类(父类>子类>分类)。
2.普通方法中,分类同名方法会覆盖主类的方法。
多个分类中的同名方法只执行一个,即后编译的分类中的方法会覆盖所有前面的同名方法。
可以把声明写在主类,实现写在分类,这样也能调用到分类里面的代码。
同样可以把声明和实现写在不同的分类文件中,还是能找到的,不过主类要相同。
3.当第一次用到类的时候,如果重写了+initialize方法,会去调用。
调用+initialize方法的时候,先调用父类的,如果父类有分类,分类的+initialize方法会覆盖掉父类的。
父类的+initialize方法不一定调用,因为分类可能会重写它。
普通方法优先级:分类>子类>父类
总结:
普通方法的优先级: 分类> 子类 > 父类, 优先级高的同名方法覆盖优先级低的。
+load方法的优先级: 父类> 子类> 分类
+load方法是在main() 函数之前调用,所有的类文件都会加载,包括分类
+load方法不会被覆盖
同一主类的不同分类中的普通同名方法调用, 取决于编译的顺序, 后编译的文件中的同名方法会覆盖前面所有的,包括主类. +load方法的顺序也取决于编译顺序, 但是不会覆盖
分类中的方法名和主类方法名一样会报警告, 不会报错
声明和实现可以写在不同的分类中, 依然能找到实现
当第一次用到类的时候, 如果重写了+ initialize方法,会去调用
当调用子类的+ initialize方法时候, 先调用父类的,如果父类有分类, 那么分类的+ initialize会覆盖掉父类的, 和普通方法差不多
父类的+ initialize不一定会调用, 因为有可能父类的分类重写了它
具体参考:https://blog.csdn.net/appleLg/article/details/79931742

13.Objective-C 消息转发机制

Objective-C 消息转发分为三个步骤:
1.动态模式 (dynamic mode)
实现动态加载,需要重写对应的方法
+(BOOL)resolveInstanceMethod:(SEL)sel;
+(BOOL)resolveClassMethod:(SEL)sel;
如果返回 YES,表示找到,并且需要动态加载(在运行时添加方法实现,而不是在编译期)实现类的声明的方法。
如果返回 NO,表示通过动态模式,没有找到方法的实现,则需要通过其他两种方式接着继续找。
2.快速前向模式 (fast forwarding mode)
需要实现下面的方法,返回代理对象:

  • (id)forwardingTargetForSelector:(SEL)aSelector;
    3.常规前向模式 (normal forwarding mode)
    常规前向模式,需要了解 NSMethodSignature和NSInvocation两个类,及其以下两个方法:
  • (NSMethodSignature *)methodSignatureForSelector:(SEL)sel;
  • (void)forwordInvocation:(NSInvocation *)anInvocation;
    methodSignatureForSelector 返回的方法签名,用于创建 NSInvocation,传入第二个方法上。
    在forwordInvocation,需要指定代理对象(receiver),执行 NSInvocation对象的方法。
    具体参考:https://zhuanlan.zhihu.com/p/24925312

14.SideTables, SideTable, weak_table, weak_entry_t

具体参考:https://blog.csdn.net/u013378438/article/details/82790332

15.关联对象实现原理

具体参考:https://www.jianshu.com/p/0f9b990e8b0a

16,如何在关联对象上使用 weak

首先我们在 setter 方法里面使用了一个weak 的局部变量 weakObj 来存储值. 并在 block 中将其捕获并返回.
由于 weakObj 是弱引用, 所以不会修改对象的引用计数. 当对象释放时, 由于 weakObj的 weak属性, 它也会在释放后指向nil. 所以当在 getter 中返回的时候, 自然也是返回 nil.
具体参考:https://www.jianshu.com/p/1b0a1f9ecf39?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

17.Autoreleasepool的数据结构和实现原理

简单说是双向链表,每张链表头尾相接,有 parent、child指针
每创建一个池子,会在首部创建一个 哨兵 对象,作为标记
最外层池子的顶端会有一个next指针。当链表容量满了,就会在链表的顶端,并指向下一张表。
自动释放池是一个个 AutoreleasePoolPage 组成的 一个page是4096字节大小,每个 AutoreleasePoolPage 以双向链表连接起来形成一个自动释放池
当对象调用 autorelease 方法时,会将对象加入 AutoreleasePoolPage 的栈中
pop 时是传入边界对象,然后对page 中的对象发送release 的消息
具体参考:https://www.jianshu.com/p/50bdd8438857

18.iOS 中的内省方法

1.判断对象类型:
-(BOOL) isKindOfClass: 判断是否是这个类或者这个类的子类的实例
-(BOOL) isMemberOfClass: 判断是否是这个类的实例
2.判断对象or类是否有这个方法
-(BOOL) respondsToSelector: 判读实例是否有这样方法
+(BOOL) instancesRespondToSelector: 判断类是否有这个方法

19关于NSNotificationCenter

1.iOS9.0之前不移除是会崩溃的,iOS9.0之后不移除是不会崩溃的。
在iOS9.0之前,通知中心对观察者对象进行unsafe_unretained 引用,当被引用的对象释放时不会自动置为nil,,也就是成了野指针。
iOS9.0之后通知中心对观察者做了弱引用。
2.不管添加通知在主线程还是子线程,接收通知的方法所在的线程是由发送通知的线程决定的。
关于实现原理参考:https://www.cnblogs.com/miaomiaocat/p/11678591.html
关于同步异步问题请参考:
https://blog.csdn.net/xubinlxb/article/details/52073803
https://www.jianshu.com/p/208568075b4f

20.关于iOS触摸事件

触摸发生时,系统内核生成触摸事件,先由IOKit处理封装成IOHIDEvent对象,通过IPC传递给系统进程SpringBoard,而后再传递给前台APP处理。
事件传递到APP内部时被封装成开发者可见的UIEvent对象,先经过hit-testing寻找第一响应者,而后由Window对象将事件传递给hit-tested view,并开始在响应链上的传递。
UIRespnder、UIGestureRecognizer、UIControl,笼统地讲,事件响应优先级依次递增。
具体参考:https://www.jianshu.com/p/c294d1bd963d

21.关于runloop

具体参考:https://www.cnblogs.com/jiangzzz/p/5619512.html

22.关于KVO

被观察者在销毁前,要移除所有的观察者,iOS10以下会崩溃,iOS11以上不会崩溃
KVO可能崩溃的原因:参考https://www.jianshu.com/p/a3acab9dfc4a
KVO简单原理:参考https://www.jianshu.com/p/24dda55b799c
KVO Options 详细介绍:参考https://www.jianshu.com/p/917770c3d3d5

23.关于GCD和NSOperation

GCD具体参考:https://juejin.im/post/5a90de68f265da4e9b592b40
NSOperation具体参考:https://www.jianshu.com/p/4b1d77054b35

24.关于离屏渲染的理解 以及解决方案

具体参考:https://www.jianshu.com/p/cff0d1b3c915

25.imageName与imageWithContentsOfFile区别

1.两者区别:
imageName 加载图片完成后,会把图片缓存到内存中,这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象;如果缓存中没有找到相应的图片对象,则从指定地方加载图片然后缓存对象,并返回这个图片对象。
而imageWithContentOfFile 则仅只加载图片不缓存。
2.两者的使用场景
imageWithContentOfFile 主要用于加载大图,只加载一次,不太需要缓存;例如用于引导页加载图片。
在不太影响性能的情况下,使用imageName,大量使用imageName方式会增加开销CPU的时间来处理这件事,会影响性能。

26.APP启动监控和优化思路

具体参考:https://www.jianshu.com/p/4acad5aafe93

27.APP耗电量检测与优化

具体参考:https://www.jianshu.com/p/10bd19df2b14

28.APP上架AppStore流程

创建APPID—电脑钥匙串导出CSR文件—选择CSR文件创建发布证书—填写APPID、BundleID、选择发布证书创建PP文件—iTunes connect创建项目、填写基本信息—Xcode Archive打包项目上传—iTunes选择ipa包发布,等待审核
具体参考:https://www.jianshu.com/p/e5ac7b05750a

29.关于路由和组件化

目前主流三种方式:
1.Url-scheme注册
2.利用Runtime实现的target-action方式(CTMediator)
3.protcol-class注册
具体参考:https://www.jianshu.com/p/72d705ecc177

30.关于线程锁

分为互斥锁和自旋锁

互斥锁:如果共享数据已经有其他线程加锁了,线程会进入休眠状态等待锁。一旦被访问的资源被解锁, 则等待资源的线程会被唤醒
包含:NSLock、pthread_mutex、NSCondition、NSConditionLock、NSRecursiveLock、dispatch_semaphore、@synchronized 、os_unfair_lock

自旋锁:如果共享数据已经有其他线程加锁了,线程会以死循环的方式等待锁,一旦被访问的资源被解锁, 则等待资源的线程会立即执行
包含:OSSpinLock、atomic
自旋锁特点:
1.自旋锁的性能高于互斥锁,因为响应速度快
2.自旋锁虽然会一直自旋等待获取锁,但不会一直占用CPU,超过了操作系统分配的时间片会被强制挂起
3.自旋锁如果不能保证所有线程都是同一优先级,则可能造成死锁。
使用场景:多核处理器情况下: 如果预计线程等待锁的时间比较短,短到比线程两次切换上下文的时间还要少的情况下,自旋锁是更好的选择。
如果时间比较长,则互斥锁是比较好的选择。 单核处理器情况下: 不建议使用自旋锁。
1、所有的锁基本都是创建锁、加锁、等待、解锁的流程,所以并不复杂。
2.如果追求锁的极致性能,可以考虑更偏底层实现的pthread_mutex互斥锁以及信号量的方式。
3.@synchronized的效率最低,但是它使用最方便,所以如果没有性能瓶颈的话使用它也不错。
具体参考:https://www.jianshu.com/p/7911d791e0e6

31.关于KVC

KVC,键值编码 通过key名直接访问对象属性或者给对象属性赋值,而不需要调用明确的存取方法,可以在运行时动态地访问和修改对象属性。
在设置或者取值的时候默认情况下会根据:_key->_iskey->key->iskey的顺序搜索成员
具体参考:
https://juejin.im/post/5e45099e518825495371f3e4
https://www.jianshu.com/p/fb1fbe5eec13

32.NSCache和NSMutableDictionary的相同点与区别

相同点:
NSCache和NSMutableDictionary功能用法基本是相同的
区别:
NSCache是线程安全的,NSMutableDictionary线程不安全,Mutable开发的类一般都是线程不安全的
当内存不足时NSCache会自动释放内存(所以从缓存中取数据的时候总要判断是否为空)
NSCache可以指定缓存的限额,当缓存超出限额自动释放内存
NSCache的Key只是对对象进行了Strong引用,而非拷贝,所以不需要实现NSCopying协议

33.layoutSubviews方法什么时候会被调用

init方法不会调用layoutSubviews,但是是用initWithFrame进行初始化时,当rect的值不为CGRectZero时,会触发
addSubview会触发layoutSubviews方法
setFrame只有当设置的frame的参数的size与原来的size不同,才会触发其view的layoutSubviews方法
滑动UIScrollView会调用scrollview及scrollview上的view的layoutSubviews方法
旋转设备只会调用VC的view的layoutSubviews方法
直接调用[self setNeedsLayout];(这个在上面苹果官方文档里有说明)
-layoutSubviews方法:这个方法默认没有做任何事情,需要子类进行重写
-setNeedsLayout方法:标记为需要重新布局,异步调用layoutIfNeeded刷新布局,不立即刷新,但layoutSubviews一定会被调用
-layoutIfNeeded方法:如果有需要刷新的标记,立即调用layoutSubviews进行布局(如果没有标记,不会调用layoutSubviews)
如果要立即刷新,要先调用[view setNeedsLayout],把标记设为需要布局,然后马上调用[view layoutIfNeeded],实现布局
在视图第一次显示之前,标记总是需要刷新的,可以直接调用[view layoutIfNeeded]

34.哪些情况会导致app卡顿,分别可以用什么方法来避免?

1.主线程中进化IO或其他耗时操作,解决:把耗时操作放到子线程中操作
2.GCD并发队列短时间内创建大量任务,解决:使用线程池
3.文本计算,解决:把计算放在子线程中避免阻塞主线程
4.大量图像的绘制,解决:在子线程中对图片进行解码之后再展示
5.高清图片的展示,解法:可在子线程中进行下采样处理之后再展示

35.App网络层有哪些优化策略?

1.优化DNS解析和缓存
2.对传输的数据进行压缩,减少传输的数据
3.使用缓存手段减少请求的发起次数
4.使用策略来减少请求的发起次数,比如在上一个请求未着地之前,不进行新的请求
5.避免网络抖动,提供重发机制

36.简述 SSL 加密的过程用了哪些加密方法,为何这么做?

SSL 加密,在过程中实际使用了 对称加密 和 非对称加密 的结合。主要的考虑是先使用 非对称加密 进行连接,这样做是为了避免中间人攻击秘钥被劫持,但是 非对称加密 的效率比较低。
所以一旦建立了安全的连接之后,就可以使用轻量的 对称加密。

37.PerformSelector 的实现原理

当调用 NSObject 的 performSelecter:afterDelay: 后,实际上其内部会创建一个 Timer 并添加到当前线程的 RunLoop 中。所以如果当前线程没有 RunLoop,则这个方法会失效。
当调用 performSelector:onThread: 时,实际上其会创建一个 Timer 加到对应的线程去,同样的,如果对应线程没有 RunLoop 该方法也会失效。

38.关于MVC、MVP、MVVM模式

MVC:
Model和View永远不能相互通信,只能通过Controller传递
Controller可以直接与Model对话(读写调用Model),Model通过NSNotification和KVO机制与Controller间接通信
Controller可以直接与View对话,通过IBoutlet直接操作View,IBoutlet直接对应View的控件(例如创建一个Button:需声明一个 IBOutlet UIButton * btn),View通过action向Controller报告时间的发生(用户点击了按钮)。Controller是View的直接数据源
优点:对于混乱的项目组织方式,有了一个明确的组织方式。通过Controller来掌控全局,同时将View展示和Model的变化分开
缺点:愈发笨重的Controller,随着业务逻辑的增加,大量的代码放进Controller,导致Controller越来越臃肿,堆积成千上万行代码,后期维护起来费时费力
MVP:
MVP模式是MVC模式的一个演化版本,其中Model与MVC模式中Model层没有太大区别,主要提供数据存储功能,一般都是用来封装网络获取的json数据;View与MVC中的View层有一些差别,MVP中的View层可以是viewController、view等控件;Presenter层则是作为Model和View的中介,从Model层获取数据之后传给View。
从MVC模式中增加了Presenter层,将UIViewController中复杂的业务逻辑、网络请求等剥离出来。
优点: 模型和视图完全分离,可以做到修改视图而不影响模型;更高效的使用模型,View不依赖Model,可以说VIew能做到对业务逻辑完全分离
缺点: Presenter中除了处理业务逻辑以外,还要处理View-Model两层的协调,也会导致Presenter层的臃肿
MVVM:
在MVVM中,view和ViewController联系在一起,我们把它们视为一个组件,view和ViewController都不能直接引用Model,而是引用是视图模型即ViewModel。 viewModel是一个用来放置用户输入验证逻辑、视图显示逻辑、网络请求等业务逻辑的地方,这样的设计模式,会轻微增加代码量,但是会减少代码的复杂性
优点: View可以独立于Model的变化和修改,一个ViewModel可以绑定到不同的View上,降低耦合,增加重用
缺点: 过于简单的项目不适用、大型的项目视图状态较多时构建和维护成本太大

38.导致Crash的原因有哪些?

1、找不到方法的实现unrecognized selector sent to instance
2、KVC造成的crash
3、EXC_BAD_ACCESS
4、KVO引起的崩溃
5、集合类相关崩溃
6、多线程中的崩溃
7、Socket长连接,进入后台没有关闭
8、Watch Dog超时造成的crash
9、后台返回NSNull导致的崩溃,多见于Java做后台服务器开发语言

39.关于定时器

iOS中常用NSTimer、CADisplayLink、GCD定时器,其中NSTimer、CADisplayLink基于NSRunLoop实现,故存在误差,GCD定时器只依赖系统内核,相对一前两者是比较准时的。
误差原因是:与NSRunLoop机制有关, 因为RunLoop每跑完一次圈再去检查当前累计时间是否已经达到定时设置的间隔时间,如果未达到,RunLoop将进入下一轮任务,待任务结束之后再去检查当前累计时间,而此时的累计时间可能已经超过了定时器的间隔时间,故会存在误差。
CADisplayLink和NSTimer会对target产生强引用,如果target又对它们产生强引用,那么就会引发循环引用。
参考:https://juejin.im/post/6863452695144071175

40.method swizzling你应该注意的点

方法交换是OC运行时特征之一,通过方法交换可以hook方法,在实现一些需求时可以达到事半功倍的效果,但使用不慎同样可能导致难以想象的后果。在使用method swizzling前都应该理解以下注意点。
1.避免交换父类方法
2.交换方法应在+load方法
3.交换方法应该放到dispatch_once中执行
4.交换的分类方法应该添加自定义前缀,避免冲突
5.交换的分类方法应调用原实现
参考:https://segmentfault.com/a/1190000015745614?utm_source=tag-newest

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

推荐阅读更多精彩内容

  • 面向对象的三大特性:封装、继承、多态 OC内存管理 _strong 引用计数器来控制对象的生命周期。 _weak...
    运气不够技术凑阅读 1,082评论 0 10
  • 禅与 Objective-C 编程艺术 (Zen and the Art of the Objective-C C...
    GrayLand阅读 1,600评论 1 10
  • 叶生福毅,南粤人,家传敦厚,其亦钟爱文艺者也!当其年轻,以忠义之怀从军,洎乎退伍求学于渝州,因翰墨缘,从吾友重赓逰...
    叶楚易阅读 510评论 0 6
  • 没有反思的人生不值得过----苏格拉底 本周目标 广州、香港住宿定下来✅ BCD银行卡实践❎ 现金流游戏...
    丹_梅阅读 231评论 0 0
  • 欲望是一个非常基本的词语,容易理解,不好解释。 以叔本华和尼采为代表的意志哲学认为,人就是欲望本身,欲...
    归来少年_85f3阅读 703评论 0 0