基础:runtime,runloop等
Category中不能添加成员变量:
Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针;objc_class结构体中,ivars是objc_ivar_list(成员变量列表)指针;methodLists是指向objc_method_list(方法定义的列表)指针的指针。在Runtime中,objc_class结构体大小是固定的,不可能往这个结构体中添加数据,只能修改。所以ivars指向的是一个固定区域,只能修改成员变量值,不能增加成员变量个数。methodList是一个二维数组,所以可以修改*methodLists的值来增加成员方法,虽没办法扩展methodLists指向的内存区域,却可以改变这个内存区域的值(存储的是指针)。因此,可以动态添加方法,不能添加成员变量。
- Extension
- 在编译器决议,是类的一部分,在编译器和头文件的@interface和实现文件里的@implement一起形成了一个完整的类。
- 伴随着类的产生而产生,也随着类的消失而消失。
- Extension一般用来隐藏类的私有消息,你必须有一个类的源码才能添加一个类的Extension,所以对于系统一些类,如NSString,就无法添加类扩展
- Category
- 是运行期决议的
- 类扩展可以添加实例变量,分类不能添加实例变量
- 原因:因为在运行期,对象的内存布局已经确定,如果添加实例变量会破坏类的内部布局,这对编译性语言是灾难性的。
FunLoop:http://www.imlifengfeng.com/blog/?p=487
程序运行,开启线程,为了保证程序持续运行,开启runloop,保证主线程不被销毁,在循环过程中处理对应的时间;我们可以把RunLoop看成一个死循环。
RunLoop对象包括Fundation中的NSRunLoop对象和CoreFoundation中的CFRunLoopRef对象。
(1)每条线程都有唯一的一个与之对应的RunLoop对象。
(2)主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建。
(3)RunLoop在第一次获取时创建,在线程结束时销毁。
线程和 RunLoop 之间是一一对应的,其关系是保存在一个全局的 Dictionary 里。线程刚创建时并没有 RunLoop,如果你不主动获取,那它一直都不会有。RunLoop 的创建是发生在第一次获取时,RunLoop 的销毁是发生在线程结束时。你只能在一个线程的内部获取其 RunLoop(主线程除外)。
[NSRunLoop currentRunLoop];
方法调用时,会先看一下字典里有没有存子线程相对用的RunLoop,如果有则直接返回RunLoop,如果没有则会创建一个,并将与之对应的子线程存入字典中。
CFRunLoopModeRef:
一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个 Source/Timer/Observer。每次调用 RunLoop 的主函数时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode。如果需要切换 Mode,只能退出 Loop,再重新指定一个 Mode 进入。这样做主要是为了分隔开不同组的 Source/Timer/Observer,让其互不影响。
instancetype和id:
(1)类方法中,以alloc或new开头
(2)实例方法中,以autorelease,init,retain或self开头
会返回一个方法所在类类型的对象,这些方法就被称为是关联返回类型的方法。换句话说,这些方法的返回结果以方法所在的类为类型。
非关联返回类型,可认为是非上面1、2两种方式而自定义的构造方法,得到的返回类型就和方法声明的返回类型一样,是id。
instancetype的作用,就是使那些非关联返回类型的方法返回所在类的类型!
(1)id在编译的时候不能判断对象的真实类型
instancetype在编译的时候可以判断对象的真实类型
(2)如果init方法的返回值是instancetype,那么将返回值赋值给一个其它的对象会报一个警告
如果是在以前, init的返回值是id,那么将init返回的对象地址赋值给其它对象是不会报错的
(3)id可以用来定义变量, 可以作为返回值, 可以作为形参
instancetype只能用于作为返回值;
但凡自定义构造方法, 返回值尽量使用instancetype, 不要使用id。