`isa`指针是否携带有关Objective-C中实例化的其他消息?

时间:2016-09-21 00:00:59

标签: ios objective-c objective-c-runtime

我一直认为isa指针指向实例化的类。并且Class的isa指针指向其metaclass。 但在一篇关于引入isa指针的文章中,作者写道:isa指针中的每个位都可以携带一些关于该对象的消息。如下所示:

[objc explain]: Non-pointer isa

从 NSObject 的初始化了解 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 ,就像:

enter image description here

我已在NSObject中添加了相关对象,但has_assoc指针中的第二位(isa)不是 1

那我怎样才能理解isa指针?

3 个答案:

答案 0 :(得分:1)

也许,你应该知道两点。

首先,在大多数情况下,将nil值传递给字典会导致从字典中删除密钥。

例如- (void)setObject:(ObjectType)object forKeyedSubscript:(id<NSCopying>)aKeyvoid 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