NSNumber
因为在从32位升级到64位后,同一个对象占用的内存会变成原来的2倍,为了节省内存和访问效率而引入了TaggedPointer. 像NSNumber,NSDate的地址不是真正的地址,如果是NSNumber@(1),@(2)
,那么地址分别是是
(__NSCFNumber *) $0 = 0xb000000000000012 (int)1
(__NSCFNumber *) $3 = 0xb000000000000022 (int)2
我们发现倒数第2位就是存储的真实值,它会以0xb......2
这样的格式展示,指针包含两部分,一部分是真实值,一部分是特殊标记。但是这样的话,如果数值过大,位数就不够了。我们测试一下,我们用一个特别大的值,@(0xEFFFFFFFFFFFFFFF)
,地址是:
(__NSCFNumber *) $5 = 0x00006000000320e0
结果很像一个指针,这个是真正的指针,它没有用到TaggedPointer。
ISA失效
虽然taggedPointer有一定的好处,但是它并不是一真正的对象,而是个伪对象,所以我们不能直接获取它的isa,否则就会报错。为了获取Isa,我们定义一个假的tempObject结构体来抽取isa指针:
struct tempObject {
Class isa;
};
ViewController *vc = [[ViewController alloc] init];
struct tempObject *oo = (__bridge struct tempObject *)number;
Class isa = oo->isa;
结果运行时报错,访问了野指针:
Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
说明它根本就没有isa指针。但是如果我们用object_getClass()
或[NSNumber Class]
来获取isa时会返正确的的Class:__NSCFNumber
。因为苹果已经伪装好了,很多runtime API里都会判断是否是TaggedPointer对象,会对它单独进行处理。
网友评论