总结了一下比较重要的知识:
1.运行时:一套c的api,api用c++实现,所有oc代码运行时,会替换为运行时的函数来执行,objc_msgSend()等函数。使用:在分类中添加属性, 替换、添加方法,获取成员列表进行解归档
2.消息循环:对事件的监听,没有事件,会进入休眠状态,有了事件被唤醒,子线程默认不开启runloop
时钟开启需要添加到运行循环,在子线程需要开启CFRunLoopRun(); 执行后 CFRunLoopStop(CFRunLoopGetCurrent());停止
3.响应者链条:事件的传递是从window到子视图传递,pointinside为yes就属于相应链条的一部分,传到最后的视图是第一响应者,然后再响应回去->superview->rootController->window->runloop->application
4.自动释放池:在消息循环监听到事件即将触发时,创建自动释放池,处理事件后,一次运行循环前,销毁自动释放池,autorelease -1当大量循环创建cup来不及处理,@autoreleasepool{} 由于子线程默认不开启运行循环,使用nsthread多线程需要手动添加释放池。
5.kvc:即是指 NSKeyValueCoding,一个非正式的Protocol。
1.字典转模型,遍历字典中所有key,去模型中查找有没有对应的属性
2.替换系统只读属性的UI,访问类的私有属性,基于运行时,动态通过以Key依次在的setter、getter、_<key>、_is<key>、get<key>等中搜索,获取、修改属性。
重写 setNilValueForKey:,防止传空崩溃
6.kvo:监听成员变量值的变化,记得移除,创建一个isa指针指向的派生类,重写setter方法,在setter方法里回调事件。被观察属性执行了 setter 方法或用kvc赋值才会回调响应,因为内部使用了kvc,所以监听只读属性会回调响应,比如:_person = newPerson是监听不到响应的。
7.Kvo与notification与delegate都是类与类之间的通讯,前两者可以一对多,后者一对一,使用多播代理可以一对多,通知耗性能,不得已用之。kvo和通知都是观察者模式,KVO是被观察者直接发送消息给观察者,是对象间的直接交互,通知则是两者都和通知中心对象交互,对象之间不知道彼此,kvo只可以监听属性变化,通知可以任意发送。代理和block在简单层级关系的交互使用方便,复杂场景代理会嵌套,block会代码块传递,通知是全局回调,更适合复杂场景,blcok与代理相比,block使用更便捷,但代理的好处是代码结构更清晰。
8.消息机制:oc中调用一个方法被转化成运行时的一个函数objc_msgSend(),通过对象的isa找到类对象,在class中会先去cache中 通过SEL查找对应函数method(cache中method列表是以SEL为key通过hash表来存储的,这样能提高函数查找速度),若 cache中未找到。再去class中的消息列表methodList中查找,若methodlist中未找到,则取superClass中查找。若能找到,则将method加 入到cache中,以方便下次查找,并通过method中的函数指针跳转到对应的函数中去执行。方法都保存在类对象的消息列表中,这个列表其实是一个字典,key是selector,value是IMP(imp是一个指针类型,指向方法的实现),并且selector和IMP之间的关系是在运行时才决定的,而不是编译时
9.消息转发机制:当调用的方法只有定义,没有实现,系统内部会依次调用三个级别的方法进行寻找,一旦找到就不继续调下一级的方法,最后找不到崩溃,可以用于拦截方法,更改方法,如:没有实现run方法,系统会先调第一级:对象方法:resolveInstanceMethod、类方法:resolveClassMethod,如果在其中实现动态添加方法,消息转发结束,如果在第一级方法里没有实现动态添加的方法,会调第二级:forwardingTargetForSelector,return一个其他对象的实例,转发给这个实例去实现方法,实现消息转发,如果没有return一个实例,会调用第三级:1.生成方法签名methodSignatureForSelector和2.给调用的对象添加签名forwardInvocation完成消息转发,第三级仍未设置,程序崩溃。
10.类的本质:是一个对象,程序中第一次使用该类的时候被创建,在整个程序中只有一份,类对象是一种数据结构,存储类的基本信息:类大小,类名称,类的版本,继承层次,以及消息与函数的映射表等。
11.__block 可以修饰对象和基本数据类型,__block会持有该对象,直到block销毁,__block修饰的内外变量是唯一的,在block内更改外部变量的值,在ARC下__block修饰的对象会引起retain在block内部把__block修饰的obj置为nil,避免循环引用,在非ARC下避免循环引用。
__weak 只在ARC中使用,只能修饰对象,可以避免循环引用,但是其会导致外部对象释放了之后,block 内部也访问不到这个对象的问题,可以通过在 block 内部声明一个 __strong的变量来指向 weakObj,使外部对象既能在 block 内部保持住,又能避免循环引用的问题
__unsafe_unretain 不会引用+1,当它指向的对象释放后,不会指向null,会保存之前的地址,野指针,不安全。
12.单例模式:优化性能,对于高耗性能、重复创建的对象如fomatter,正则对象的创建等,工具类使用单例,缺点,写多了占内存。优点,效率高
14.代理模式:可以解耦合,类与类之间不需要知道彼此的存在,系统大量用到这个模式,tableview,collectionview,pickview等等。
15.观察者模式:解耦合将改变通知给所有对象,系统的通知用的这种模式,优点,使用方便,缺点,耗性能
16.MVVM:解耦合,View代表ViewController和View,在ViewController中持有自定义View属性,在View中实现绘制和数据展示,View中持有ViewModel属性,VM加载数据,处理数据,处理业务逻辑,给M赋值,整个ViewController被架空,只负责导航,优势:视图与数据解耦合,控制器与视图数据解耦合,每一个view拥有自己特有的视图绘制和数据,内部完成数据赋值。当不同的页面有相同的视图模块时,可以直接引用同一个视图模块,便于复用。耦合度最低,使用灵活,方便维护。
17.MVC:C是控制器,V是视图,M是模型,C持有V和M,负责加载数据,处理业务逻辑,给M赋值,将数据传给V,展示更新UI。
18.优化:用instrument工具优化内存,定位耗性能高的代码,1.使用单例优化2.优化自动行高:系统的自带的自动行高耗性能,选择采用布局计算行高,数据加载后创建一个单例cell,赋值布局获取行高,赋值给viewmodel有了高度,在数据源方法返回这个高度,用coreAnimation或JPFPSStatus 看帧率是否正常3.按需加载优化,快速滑动cell列表,定义一个数组,根据scrollview滑动松手方法里给数组加需要赋值的cell的indexpath对象 开始滑动,滑动停止移除nil ,在cell的赋值中判断数组为空赋值,不为空,给对应的indexpath赋值,其余不赋值。不能在scroll的方法里赋值,耗性能4.采用yykit框架更流畅,优化图片绘制、转模型,异步渲染等方式优化5.重用cell6.使用UI格式控制的单例代替宏定义的一些全局变量,使用static inline内联函数代替宏定义
19.GCD和NSOperation区别
- GCD多线程:1、dispatch_group调度组 实现并发任务都执行完后回调执行。2、dispatch_barrier实现并发任务都执行后再执行另外的任务结束后,再并发执行任务。调度组也可以实现,只是barrier更简单。3、dispatch_semaphore信号量相当于最大并发数,可以控制线程阻塞,实现并发个数控制,异步任务顺序执行。通过wait、signal两个函数减、加信号量的个数,当信号量=0,执行wait函数,阻塞当前线程,等待异步任务执行完,执行signal函数,当前阻塞的线程继续执行。
21.NSCache:与nsmutabledictionary类似,不同点:1.系统内存很低时,自动释放缓存对象。2.线程安全,在多线程中不需要加锁。3. 对键进行强引用,不遵守nscoding协议,setObject时,不会对键名copy,0成本。
22.sdwebimage:先以url为键从nscache内存中取到展示,没有再从沙盒缓存中取,有就加入内存缓存,展示,没有去下载,下载前,先看有没有操作缓存,有就return。没有就开启异步下载任务,url为键加入操作缓存,下载完成加入内存缓存,加入沙盒缓存,移除操作缓存,刷新UI。
23.block三种类型
NSStackBlock 存储于栈区
NSGlobalBlock 存储于程序数据区
NSMallocBlock 存储于堆区
引用局部变量存在栈区,引用全局静态或不引用变量存在程序数据区,在mrc下copy后存在堆区。在arc下,引用局部变量的时候,虽然也存在栈区,但在给block赋值的时候,系统自动copy到了堆区。
24.内存分配
代码区:存放函数体的二进制代码
数据区:全局,静态和常量是分配在数据区中的,数据区包括bss(未初始化数据区)和初始化数据区,程序启动时候分配。
堆区:用于存放动态分配的对象, 当你使用 malloc和new 等进行分配时,所得到的空间就在堆中。低地址向高地址生长。
栈区:主要用来存放局部变量, 传递参数, 存放函数的返回地址。