1.alloc init new
1.alloc
--1.开辟存储空间
--2.将所有的属性设置为0
--3.返回当前实例对象的地址
2.init(构造方法)
--1.初始化成员变量 但是默认情况下init的实现是什么都没有做
--2.返回初始化后的实例对象地址
其中 alloc 和 init 返回的地址是同一个地址
3.new
Person*p= [Person new];
//其中new做了3件事情
--1.开辟存储空间 --->alloc
--2.初始化所有属性 --->init
--3.返回对象地址
//等价于
Person*p1 = [Person alloc];
Person*p2 = [p1 init];
4.alloc init 具体流程如下
Person*p1 = [Person alloc];
Person*p2 = [p1 init];
--1.使用到某一个类 就在堆中创建该类的类对象 该对象中保存了该类所有的属性和方法
--2.alloc 在堆中开辟存储空间 创建该类对象的实例对象 并将其所有的属性都置为0 将内存地址返回给局部变量p1 局部变量在栈中
--3.init 在类对象中寻找init方法(直到找到NSObject init)默认情况下init方法是一个空实现,返回调用对象的地址
在栈中开辟出p2 同样指向Person实例对象
2.重写构造方法 init
3.instancetype 和 id 的区别
instabcetype 和 id 都是万能指针
instancetype 在编译时可以判断返回对象的真实类型 ,防止运行时崩溃
id 在编译时 无法判断返回对象的真实类型 ,
id 可以作为 参数 返回值 和 参数(本质也是一个变量)
instancetype 只能作为函数返回值
4.类工厂方法在继承中的注意
apple 规范
--1.工厂方法一定是类方法
--2.方法名称以类名称开头,首字母小写
--3.一定有返回值,id/instancetype
注意
但凡自定义类工厂方法,在类工厂方法中创建对象一定不要使用类名称创建对象
一定使用self 创建,代表当前调用类
5.类的本质
类的本质其实也是一个对象(类对象),
--1.这个对象会在这个类第一次使用的时候创建
--2. 只要有了类对象,将来就可以通过类对象来创建实例对象
--3.实例对象中有一个isa指针,指向自己的类对象,
--4.类对象中保存了当前对象所有的对象方法,当给一个实例对象发送消息的时候,会根据实例对象的isa指针去对应的类对象中查找
例如:
这样一段代码
--1.Person 类会会被加载进代码区
--2.Person alloc 时 该类第一次使用 在堆中创建Person类对象 (Person 类对象中有Person 对象所有的属性和对象方法列表),alloc方法会在堆中创建Person实例对象,并且将所有的对象属性都赋值为0 并返回该实例的地址,赋值给在栈区被创建Person类型指针p
--3.其中Person 类对象也是一个对象 同样也具备isa指针,该指针指向Person的元类对象,该元类对象内保存有该类的所有类方法列表
--4.Person元类对象同样也是一个对象,同样具备isa指针,其指向根元类对象 ,该对象内,也保存有根元类对象的类方法列表(+(instancetype)new 等),OC中NSObject 为所有类的基类,so 这时根元类对象即为NSObjcet的元类对象
--5.而例如调用[p setAge:30]时,首先根据栈中的指针p找到 堆中Person实例对象,Person实例对象,找到其isa指针指向的Person类对象 在实例方法列表中找到setAge方法 并调用
--6. 而例如调用[Person test]时,会直接找到堆中的Person类对象,并根据类对象的isa指针找到Person元类对象 并从元类对象中类方法列表找到test类方法 并调用,若该类中并没有找到该类方法,就去父类中寻找,知道找到该类方法为止
所有类的“类对象”继承关系就是所有“元类对象”的继承关系 这样的设计思路方便方法的查找
6.类对象
7.类的启动过程
--1.只要程序启动,就会将类的代码加载到内存中,放在代码区
--2.+(void)load;
load 方法会在当前类被加载到内存的时候调用,有且仅会只有一次
--3.+(void)initialize;
initialize 方法会在当前类第一次被使用的时候调用(既类对象被创建的时候调用),无论使用多少次该类,该方法只会被调用一次
--4.在继承关系中
+load 和 +Initialize 方法严格遵循父类到子类关系顺序调用
且在initialize 方法中 若子类对象被实例化,父类initialize 方法同样会被调用,且在子类之前
8.SEL类型
SEL类型代表着方法的签名,在类对象的方法列表中存储着该签名与方法的对应关系
--1.每个类的方法列表都存储在类对象中
--2.每一个方法都有一个与之对应的SEL类型的对象
--3.根据一个SEL对象就可以找到方法的地址,进而调用方法
SEL类型的定义
typedef struct objc_selector *SEL
例如:[p test]
首先会将test 这个方法名包装成SEL类型的数据
根据SEL到该类的类对象上去找对应方法的实现,如果找到了就执行,找不到就向父类去寻找直到基类NSObject 若未找到则报错
注意:在这个操作过程中有缓存,第一次寻找时是一个一个逐个寻找,非常消耗性能,再后来就是直接使用