一个简单的例子
先定义一个继承于NSObject的对象Test
@interface Test : NSObject
@end
运行
Test *t0 = [Test alloc];
Test *t1 = [t0 init];
Test *t2 = [t0 init];
NSLog(@"%@ -- %p -- %p",t0,t0,&t0);
NSLog(@"%@ -- %p -- %p",t1,t1,&t1);
NSLog(@"%@ -- %p -- %p",t2,t2,&t2);
打印结果
<Test: 0x6000007e5660> -- 0x6000007e5660 -- 0x7ffeedeeb188
<Test: 0x6000007e5660> -- 0x6000007e5660 -- 0x7ffeedeeb180
<Test: 0x6000007e5660> -- 0x6000007e5660 -- 0x7ffeedeeb178
可以看到前两个打印的值是一样,最后一个值不同,这三个值分别代表:内容、内存地址、指针地址
关于init方法,从源代码分析,就是返回了alloc时创建的地址
+ (id)init {
return (id)self;
}
可以分析到上述代码是创建了3个指针分别指向同一地址,用下图表示:
alloc的流程图
其中核心方法是
instanceSize(extraBytes) //计算内存空间大小
malloc_zone_calloc((malloc_zone_t *)zone, 1, size); //开辟内存
initInstanceIsa(cls, hasCxxDtor) //关联对应类
还有new
+ (id)new {
return [callAlloc(self, false/*checkNil*/) init];
}
本义上new和alloc init是一样的
但是最好用alloc init
原因是init是一个构造方法,你可能会将init方法重写,这样new就调用不到重写后的方法
最后关怎么确定object的空间大小
object自带了一个isa的指针占用8字节
@interface Test : NSObject
@property (strong, nonatomic) NSString *name; //占8字节
@property (assign, nonatomic) int age; //占4字节
@end
上面的Test类总共需要8+8+4=20字节
但开辟时是16字节位对齐的,所以实际需要32位
//16字节位对齐
static inline size_t align16(size_t x) {
return (x + size_t(15)) & ~size_t(15);
}