我一直认为isa
指针指向实例化的类。并且Class的isa
指针指向其metaclass
。
但在一篇关于引入isa
指针的文章中,作者写道:isa
指针中的每个位都可以携带一些关于该对象的消息。如下所示:
[objc explain]: Non-pointer isa
1 bit indexed 0 is raw isa, 1 is non-pointer isa.
1 bit has_assoc Object has or once had an associated reference. Object with no associated references can deallocate faster.
1 bit has_cxx_dtor Object has a C++ or ARC destructor. Objects with no destructor can deallocate faster.
30 bits shiftcls Class pointer's non-zero bits.
9 bits magic Equals 0xd2. Used by the debugger to distinguish real objects from uninitialized junk.
1 bit weakly_referenced Object is or once was pointed to by an ARC weak variable. Objects not weakly referenced can deallocate faster.
1 bit deallocating Object is currently deallocating.
1 bit has_sidetable_rc Object's retain count is too large to store inline.
19 bits extra_rc
但在我的测试中,我发现低三位总是 0 ,就像:
我已在NSObject
中添加了相关对象,但has_assoc
指针中的第二位(isa
)不是 1 。
那我怎样才能理解isa
指针?
答案 0 :(得分:1)
也许,你应该知道两点。
首先,在大多数情况下,将nil
值传递给字典会导致从字典中删除密钥。
例如- (void)setObject:(ObjectType)object forKeyedSubscript:(id<NSCopying>)aKey
和void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)
。
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
dic[@"name"] = @"酷酷的哀殿";
dic[@"name"] = nil;
NSLog(@"%@", dic);// it's output is `{}`.
其次,您应该知道目标设备的字节顺序。
您可以按照以下代码进行测试。
int msg = 0x01020304;
char *buffer = (char *)&msg;
printf("%d %d %d %d\n", buffer[0], buffer[1], buffer[2], buffer[3]);
在我的x86-64设备中,它的输出为4 3 2 1
。
因此,当我更改has_assoc
时,最后一个字节将会发生变化。
在指针中,它将添加/减去2
。
isa: 0x1dffff795ca0f1
isa: 0x1dffff795ca0f3
对于isa_t
,您可以使用以下代码获取has_assoc
。
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
int main() {
// extra_rc must be the MSB-most field (so it matches carry/overflow flags)
// indexed must be the LSB (fixme or get rid of it)
// shiftcls must occupy the same bits that a real class pointer would
// bits + RC_ONE is equivalent to extra_rc + 1
// RC_HALF is the high bit of extra_rc (i.e. half of its range)
// future expansion:
// uintptr_t fast_rr : 1; // no r/r overrides
// uintptr_t lock : 2; // lock for atomic property, @synch
// uintptr_t extraBytes : 1; // allocated with extra bytes
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
struct isa_t {
uintptr_t indexed : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 19;
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
};
NSLog(@"arm64");
static void *someKey = &someKey;
id object = [NSObject new];
struct isa_t *isa = (__bridge struct isa_t *)object;
NSLog(@"%d", isa->has_assoc);
objc_setAssociatedObject(object, someKey, @"Hello World!", OBJC_ASSOCIATION_RETAIN);
NSLog(@"%d", isa->has_assoc);
NSLog(@"%p", *(void * *)(__bridge void *)object);
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# define ISA_MAGIC_MASK 0x001f800000000001ULL
# define ISA_MAGIC_VALUE 0x001d800000000001ULL
struct isa_t {
uintptr_t indexed : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 8;
# define RC_ONE (1ULL<<56)
# define RC_HALF (1ULL<<7)
};
NSLog(@"x86_64");
static void *someKey = &someKey;
id object = [NSObject new];
struct isa_t *isa = (__bridge struct isa_t *)object;
NSLog(@"%d", isa->has_assoc);
objc_setAssociatedObject(object, someKey, @"Hello World!", OBJC_ASSOCIATION_RETAIN);
NSLog(@"%d", isa->has_assoc);
NSLog(@"%p", *(void * *)(__bridge void *)object);
# else
// Available bits in isa field are architecture-specific.
# error unknown architecture
# endif
return 0;
}
答案 1 :(得分:0)
将关联对象设置为值nil
是无操作,并且不会添加到关联对象侧表。因此,它的isa
标记不会更改。
请参阅以下示例,以显示标记位是否有效:
NSObject *object = [NSObject new];
NSLog(@"isa: %p ", *(void **)(__bridge void *)object);
static void *someKey = &someKey;
objc_setAssociatedObject(object, someKey, nil, OBJC_ASSOCIATION_RETAIN);
NSLog(@"isa: %p ", *(void **)(__bridge void *)object);
对我来说,OSX 10.11输出:
2016-09-22 14:37:20.132 TestProj[95942:1117770] isa: 0x1dffff757a50f1 2016-09-22 14:37:24.208 TestProj[95942:1117770] isa: 0x1dffff757a50f1
但是如果我将值从nil更改为实际指针值:
objc_setAssociatedObject(object, someKey, @"Hello World!", OBJC_ASSOCIATION_RETAIN);
我得到(预期)输出,其中包括在指针中设置的标记位:
2016-09-22 14:40:24.190 TestProj[96095:1121411] isa: 0x1dffff757a50f1 2016-09-22 14:40:24.191 TestProj[96095:1121411] isa: 0x1dffff757a50f3
答案 2 :(得分:-1)
您在模拟器上进行了测试。你链接的文章说:
64位iOS模拟器目前不使用非指针isa。在真正的arm64设备上测试你的代码。
您必须在设备上测试才能看到非指针isa
。