1 ARC和MRC的区别
ARC自动的引用计数,LVVM编译器会在“编译”的时候 帮我们在代码合适的地方添加release、retarn、autorelease等添加计数器或者减少计数器操作
MRC手动的引用计数,需要程序员手动的去release,retine。
2 App的启动分为哪几种
1 冷启动:App重启后启动,不再内存里也没有进程存在。
2 热启动:App最近结束后再启动,有部分在内存但没有进程存在。
3 重启:APP没结束,只是暂停,全在内存中,进程也存在。
3 +load方法
1 调用时机是在AppDelegate前
2 load方法的调用顺序
2.1 父类子类都实现了load方法的话,两者的都会被调用,父类的先调用,子类的后调用。
2.2 如果子类未实现load方法,在加载该子类,不会再调用父类的方法。
2.3 如果类和 category都实现了load方法,类先执行,category后执行。
2.4 当多个category都实现了load方法,都会执行,顺序和Compile Sources 中的的顺序有关。
2.5 load方法是Runtime直接拿到load的IMP直接去调用的。
4 category相关
如果category添加与原类相同的同名方法,会覆盖原类的方法,只执行分类的方法。
当多个category有同样名称的分类方法名称时,谁在最后编译就执行谁。
5 category和Extension的区分
5.1 category分类中只能扩充方法,不能扩展属性和成员变量(写成员变量会直接报错),通过runtime可以强加属性,
5.2 category分类声明了一个属性,那么分类只会生成这个属性的set,get方法声明。
6 Block类型
6.1 GlobalBlock 存储在数据区
6.2 StackBlock 存储在栈区
6.3 MallocBlock 存储在堆区
3种block的场景
// 1. 内部没有调用外部变量的blockvoid(^block1)(void)=^{NSLog(@"Hello");};
// 2. 内部调用外部变量的blockinta=10; void(^block2)(void)=^{NSLog(@"Hello - %d",a);};
// 3. 直接调用的block的classNSLog(@"%@ %@ %@",[block1 class],[block2 class],[^{NSLog(@"%d",a);}class]);
1 GlobalBlock 2 StackBlock 3 MallocBlock
什么情况下blcok会被拷贝
在ARC下,将一个Block赋值给一个非__weak修饰的变量会执行拷贝外,还有以下情况会执行:
显式调用Block的copy方法时;
赋值给一个具有copy修饰的Block属性时;
在ARC下,向函数或者方法传递Block时(MRC下需要手动copy);
调用Coaca框架中方法名中含有usingBlock的方法时;
调用GCD的API时。
7 AutoreleasePool
AutoreleasePool使用的是 AutoreleasePoolPage管理,AutoreleasePoolPage是一个双向的链表,除了用来存放内部的成员变量,剩下的空间都会用来存放autorelease对象的地址,autoreleasepool会自动释放内存。
8 OC的消息机制
消息传递:
1 方法的调用会通过发送消息来调用 “objc_msgSend”来传递
2 第一步 根据对象(类对象,实例对象)的isa的指针找到所属的类
3 第二步 根据类对象里面的catch方法列表进行查找,根据Selector方法名来获取对应的IMP,开始调用。
3 第三步 如果没找到对应的实现IMP,会继续查找类对象里面的class_rw_t里面的methods(方法列表),从而遍历,找到方法所属的IMP,如果找到了就是添加到catch表里面,然后调用不再进行下一步。
4 第四步 如果第三步也没有找到,会根据类对象里面的superclass(父类)指针,查找父类的catch,如果还没有找到,会继续查找到父类的class_rw_t里面的methodslist(方法列表),从而遍历,找到方法所属的IMP,如果查找到则会添加到catch表里面
5 第五部 如果四步没有找到,就继续找到元类。
6 第六步,如果元类还没有找到,就会找到nsobject里面,如果再没有找到,就进入动态解析里面。
动态解析:
1 当消息传递,没有找到对应的IMP的时候,就会进入动态解析中。
2 第一步会调用 +(BOOL)resolveClassMethod:(SEL)sel; 类方法
+(BOOL)resolveInstanceMethod:(SEL)sel; 实例方法
2.1 我们可以通过“runtime的class_addMethod"实现这两个方法来添加对应的IMP
2.2 如果添加后,返回true,没有添加则调用父类方法。
2.3 注意:其实返回true或者false,结果都是一样的,再次调消息传递步骤。
3 第二部:
3.1 会调用 -(id)forwardingTargetForSelector:(SEL)aSelector方法,我们可以在这里返回一个响应aSelector的对象。当返回不为nil的时候,系统会继续再次走消息方法,继续查找对应的IMP
3.2 如果第一步返回nil或者self,此时系统会继续走这里-(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector,需要返回aSelector的一个签名
3.3 如果返回了签名,就会到这里-(void)forwardInvocation:(NSinvocation*)anInvocation,相应的我们可以根据anInvocation,可以获取到参数,target,方法名等,再次操作的空间就很多了。
9 weak属性是怎么实现的
9.1使用weak关键字修饰的对象在销毁的时候,指针会置为nil,而weak的底层是将指针和对象以key-value的形式存入哈希表,使用__weak的时候,底层会调用 id objc_storeWeak(id * location, id newobj)传递两个参数。第一个参数为指针,第二个参数是指针指向的对象。
9.2 继续调用storeWeak(location,(objc_object *)newObj)
第一个参数是指针,第二个参数是对象的地址
再次方法里面会根据对象地址生成一个SlideTables对象
9.3 调用 id weak_register_no_lock(weak_table_t *weak_table, id referent_id, id *referrer_id,bool crashIfDeallocting)
weak_table则为slideTables的一个属性,referent_id为对象,referrer_id则为那个弱应用的指针
在里面会根据对象地址和指针生成一个weak_entry_t
9.4 会继续调用static void weak_entry_insert(weak_table_t *weak_table, weak_entry_t*new_entry)
10 App启动流程及优化
App的启动流程
10.1 解析info.plist
加载相关信息,例如闪频
沙箱(sandbox)建立,权限检查。
10.2 Mach-0加载
如果是胖二进制文件,寻找合适当前CPU类别的部分
加载所有依赖的Mack-0文件(递归调用Mach-0加载的方法)
定位内部,外部指针引用,例如字符串,函数等
实行声明为_attribute_((constructor))的C函数
加载分类(category)中的方法
C++静态对象加载,调用objc的+load函数
10.3 程序执行阶段
调用main()
调用UIApplicationMain()
调用applicationWillFinishLaunching代理方法
11 不同类型的对象用copy还是strong
NSArray,NSString用copy 会执行深拷贝,从新分配内存,不会影响之前的,用strong的话是指针拷贝,会改变原来的。
NSMutableArray,NSMutableDictionary 用strong,用copy的话会变为不可变类型,增删改查会报错。
12 网络7层协议从高到底
应用层-表示层-会话层-传输层-网络层-数据链路层-物理层