isa: 对象的第一个属性必然是isa ,来源是继承NSObject
@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
---初始化isa
inline void
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor)
{
assert(!isTaggedPointer());
if (!nonpointer) {
isa.cls = cls;
} else {
assert(!DisableNonpointerIsa);
assert(!cls->instancesRequireRawIsa());
isa_t newisa(0);
#if SUPPORT_INDEXED_ISA
assert(cls->classArrayIndex() > 0);
newisa.bits = ISA_INDEX_MAGIC_VALUE;
// isa.magic is part of ISA_MAGIC_VALUE
// isa.nonpointer is part of ISA_MAGIC_VALUE
newisa.has_cxx_dtor = hasCxxDtor;
newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else
newisa.bits = ISA_MAGIC_VALUE;
// isa.magic is part of ISA_MAGIC_VALUE
// isa.nonpointer is part of ISA_MAGIC_VALUE
newisa.has_cxx_dtor = hasCxxDtor;
newisa.shiftcls = (uintptr_t)cls >> 3;
#endif
// This write must be performed in a single store in some cases
// (for example when realizing a class because other threads
// may simultaneously try to use the class).
// fixme use atomics here to guarantee single-store and to
// guarantee memory order w.r.t. the class index table
// ...but not too atomic because we don't want to hurt instantiation
isa = newisa;
}
}
isa < ----- > cls
LGPerson *object = [LGPerson alloc];
打印当前类的结构
x/4gx object
0x101a2c940: 0x001d800100001131 0x0000000000000000
0x101a2c950: 0x0000000101a2ca20 0x0000000101a2cc60
打印当前二进制isa
Mark:「p/t2进制 p/x 16进制 p/o 8进制 p/d10进制打印」
p/t 0x001d800100001131
(long) $1 = 0b0000000000011101100000000000000100000000000000000001000100110001
打印当前类class
p/x LGPerson.class
(Class) $2 = 0x0000000100001130 LGPerson
打印当前类机构二进制
《《《newisa.shiftcls = (uintptr_t)cls >> 3;》》》
p/t (uintptr_t)LGPerson.class
(uintptr_t) $3 = 0b0000000000000000000000000000000100000000000000000001000100110000
右移动三位
p/t $3>>3
(uintptr_t) $4 = 0b0000000000000000000000000000000000100000000000000000001000100110
isa 指针右移动三位
p/t $1>>3
(long) $5 = 0b0000000000000011101100000000000000100000000000000000001000100110
然后再左移动
p/t $5<<17
(long) $6 = 0b0110000000000000010000000000000000000100010011000000000000000000
右移动17位
p/t $6>>17
(long) $7 = 0b0000000000000000001100000000000000100000000000000000001000100110
$5 --$7 比较发现后面是一样的
我们还可以通过这个方法去查看:
当前对象 通过这个方法拿到一个类。他是怎样关联的呢?
object_getClass(object);
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
inline Class
objc_object::getIsa()
{
Mark:---------👇
if (!isTaggedPointer()) return ISA();
uintptr_t ptr = (uintptr_t)this;
if (isExtTaggedPointer()) {
uintptr_t slot =
(ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
return objc_tag_ext_classes[slot];
} else {
uintptr_t slot =
(ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
return objc_tag_classes[slot];
}
}
inline Class
objc_object::ISA()
{
assert(!isTaggedPointer());
#if SUPPORT_INDEXED_ISA
if (isa.nonpointer) {
uintptr_t slot = isa.indexcls;
return classForIndex((unsigned)slot);
}
return (Class)isa.bits;
#else
Mark:---------👇 ISA_MASK:相当于一个掩码
return (Class)(isa.bits & ISA_MASK);
#endif
}
p/x LGPerson.class
(Class) $1 = 0x0000000100001130 LGPerson
p/x 0x001d800100001131 & 0x00007ffffffffff8
(long) $2 = 0x0000000100001130
po 一下当前的指针 就会得到当前的类
po 0x0000000100001130
LGPerson
isa 的结构在arm64 和x86结构下是不一样的
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
# define ISA_BITFIELD \
uintptr_t nonpointer : 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)
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# define ISA_MAGIC_MASK 0x001f800000000001ULL
# define ISA_MAGIC_VALUE 0x001d800000000001ULL
# define ISA_BITFIELD \
uintptr_t nonpointer : 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)
# else
# error unknown architecture for packed isa
# endif
类在内存里面只有一份: 对象是可以创建多个;
//MARK: - 分析类对象内存存在个数
void lgTestClassNum(){
Class class1 = [LGPerson class];
Class class2 = [LGPerson alloc].class;
Class class3 = object_getClass([LGPerson alloc]);
Class class4 = [LGPerson alloc].class;
NSLog(@"\n%p-\n%p-\n%p-\n%p",class1,class2,class3,class4);
}
2019-12-22 15:12:13.588387+0800 001-对象isa[32132:1886315]
0x100002420-
0x100002420-
0x100002420-
0x100002420
类-元类
LGPerson *object = [LGPerson alloc];
我们x一下内存结构
x/4gx object.class
0x100001130: 0x001d800100001109 0x0000000100aff140
0x100001140: 0x0000000100fa2090 0x0000000200000003
然后打印一下当前指针的对象:
po 0x100001130
LGPerson
居然又指向了LGPerson 这个类??!!
A->b->A
实际上这个是meta class 元类
Mark:
类:我们在创建的一个类的时候 向系统申请开辟内存空间,系统会根据这个来给我们实例化出来。在系统中只存在一份。
元类:系统编译出来的,来源于编译器,根据创建的类,来生成元类,方便后期的存储使用。
对象的isa --> 类 isa --> 元类 -->根元类
屏幕快照 2019-12-22 下午3.33.02.png
isa流程图.png
union 联合体
isa_t 是一个联合体,Class cls 与 uintptr_t bits 是互斥的,在初始化isa 的时候,如果是nopointisa 就对当前的bit 进行一系列的操作。如果不是nopointisa 就直接关联当前的cls 就好了。只需要表达类的信息,类的指向就行了。
截屏2019-12-18下午6.19.24.png
网友评论