struct objc_object {
private:
isa_t isa;
public:// ISA() assumes this is NOT a tagged pointer object
Class ISA(bool authenticated = false);// rawISA() assumes this is NOT a tagged pointer object or a non pointer ISA
Class rawISA();// getIsa() allows this to be a tagged pointer object
Class getIsa();
uintptr_t isaBits()const;// initIsa() should be used to init the isa of new objects only.// If this object already has an isa, use changeIsa() for correctness.// initInstanceIsa(): objects with no custom RR/AWZ// initClassIsa(): class objects// initProtocolIsa(): protocol objects// initIsa(): other objectsvoidinitIsa(Class cls /*nonpointer=false*/);voidinitClassIsa(Class cls /*nonpointer=maybe*/);voidinitProtocolIsa(Class cls /*nonpointer=maybe*/);voidinitInstanceIsa(Class cls, bool hasCxxDtor);// changeIsa() should be used to change the isa of existing objects.// If this is a new object, use initIsa() for performance.
Class changeIsa(Class newCls);
bool hasNonpointerIsa();
bool isTaggedPointer();
bool isTaggedPointerOrNil();
bool isBasicTaggedPointer();
bool isExtTaggedPointer();
bool isClass();// object may have associated objects?
bool hasAssociatedObjects();voidsetHasAssociatedObjects();// object may be weakly referenced?
bool isWeaklyReferenced();voidsetWeaklyReferenced_nolock();// object may have -.cxx_destruct implementation?
bool hasCxxDtor();// Optimized calls to retain/release methods
id retain();voidrelease();
id autorelease();// Implementations of retain/release methods
id rootRetain();
bool rootRelease();
id rootAutorelease();
bool rootTryRetain();
bool rootReleaseShouldDealloc();
uintptr_t rootRetainCount();// Implementation of dealloc methods
bool rootIsDeallocating();voidclearDeallocating();voidrootDealloc();
private:voidinitIsa(Class newCls, bool nonpointer, bool hasCxxDtor);// Slow paths for inline control
id rootAutorelease2();
uintptr_t overrelease_error();#ifSUPPORT_NONPOINTER_ISA// Controls what parts of root{Retain,Release} to emit/inline// - Full means the full (slow) implementation// - Fast means the fastpaths only// - FastOrMsgSend means the fastpaths but checking whether we should call// -retain/-release or Swift, for the usage of objc_{retain,release}enum class RRVariant {
Full,
Fast,
FastOrMsgSend,};// Unified retain count manipulation for nonpointer isainline id rootRetain(bool tryRetain, RRVariant variant);inline bool rootRelease(bool performDealloc, RRVariant variant);
id rootRetain_overflow(bool tryRetain);
uintptr_t rootRelease_underflow(bool performDealloc);voidclearDeallocating_slow();// Side table retain count overflow for nonpointer isastruct SidetableBorrow { size_t borrowed, remaining;};voidsidetable_lock();voidsidetable_unlock();voidsidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);
bool sidetable_addExtraRC_nolock(size_t delta_rc);
SidetableBorrow sidetable_subExtraRC_nolock(size_t delta_rc);
size_t sidetable_getExtraRC_nolock();voidsidetable_clearExtraRC_nolock();#endif// Side-table-only retain count
bool sidetable_isDeallocating();voidsidetable_clearDeallocating();
bool sidetable_isWeaklyReferenced();voidsidetable_setWeaklyReferenced_nolock();
id sidetable_retain(bool locked = false);
id sidetable_retain_slow(SideTable& table);
uintptr_t sidetable_release(bool locked = false, bool performDealloc = true);
uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true);
bool sidetable_tryRetain();
uintptr_t sidetable_retainCount();#ifDEBUG
bool sidetable_present();#endif};
struct objc_class : objc_object {
Class superclass;constchar*name;
uint32_t version;
uint32_t info;
uint32_t instance_size;struct old_ivar_list *ivars;struct old_method_list **methodLists;
Cache cache;struct old_protocol_list *protocols;// CLS_EXT onlyconst uint8_t *ivar_layout;struct old_class_ext *ext;voidsetInfo(uint32_t set){OSAtomicOr32Barrier(set,(volatile uint32_t *)&info);}voidclearInfo(uint32_t clear){OSAtomicXor32Barrier(clear,(volatile uint32_t *)&info);}// set and clear must not overlapvoidchangeInfo(uint32_t set, uint32_t clear){ASSERT((set & clear)==0);
uint32_t oldf, newf;do{
oldf = this->info;
newf =(oldf | set)&~clear;}while(!OSAtomicCompareAndSwap32Barrier(oldf, newf,(volatile int32_t *)&info));}
bool hasCxxCtor(){// set_superclass propagates the flag from the superclass.return info & CLS_HAS_CXX_STRUCTORS;}
bool hasCxxDtor(){returnhasCxxCtor();// one bit for both ctor and dtor}// Return YES if the class's ivars are managed by ARC, // or the class is MRC but has ARC-style weak ivars.
bool hasAutomaticIvars(){return info &(CLS_IS_ARC | CLS_HAS_WEAK_WITHOUT_ARC);}// Return YES if the class's ivars are managed by ARC.
bool isARC(){return info & CLS_IS_ARC;}
bool hasCustomRR(){return true;}
bool hasCustomAWZ(){return true;}
bool forbidsAssociatedObjects(){// Old runtime doesn't support forbidding associated objects.return false;}
bool instancesHaveAssociatedObjects(){return info & CLS_INSTANCES_HAVE_ASSOCIATED_OBJECTS;}voidsetInstancesHaveAssociatedObjects(){setInfo(CLS_INSTANCES_HAVE_ASSOCIATED_OBJECTS);}
bool shouldGrowCache(){return info & CLS_GROW_CACHE;}voidsetShouldGrowCache(bool grow){if(grow)setInfo(CLS_GROW_CACHE);elseclearInfo(CLS_GROW_CACHE);}// +initialize bits are stored on the metaclass only
bool isInitializing(){returngetMeta()->info & CLS_INITIALIZING;}// +initialize bits are stored on the metaclass onlyvoidsetInitializing(){getMeta()->setInfo(CLS_INITIALIZING);}// +initialize bits are stored on the metaclass only
bool isInitialized(){returngetMeta()->info & CLS_INITIALIZED;}// +initialize bits are stored on the metaclass onlyvoidsetInitialized(){getMeta()->changeInfo(CLS_INITIALIZED, CLS_INITIALIZING);}
bool isLoadable(){// A class registered for +load is ready for +load to be called// if it is connected.returnisConnected();}
IMP getLoadMethod();
bool isFuture();
bool isConnected();constchar*mangledName(){return name;}constchar*demangledName(){return name;}constchar*nameForLogging(){return name;}
bool isRootClass(){return superclass == nil;}
bool isRootMetaclass(){returnISA()==(Class)this;}
bool isMetaClass(){return info & CLS_META;}// NOT identical to this->ISA() when this is a metaclass
Class getMeta(){if(isMetaClass())return(Class)this;elsereturn this->ISA();}// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceStart(){// This is not simply superclass->instance_size.// superclass->instance_size is padded to its sizeof() boundary, // which may envelop one of this class's ivars. // That in turn would break ARC-style ivar layouts.// Instead, we use the address of this class's first ivar when possible.if(!superclass)return0;if(!ivars || ivars->ivar_count ==0)return superclass->instance_size;return ivars->ivar_list[0].ivar_offset;}// Class's instance start rounded up to a pointer-size boundary.// This is used for ARC layout bitmaps.
uint32_t alignedInstanceStart(){returnword_align(unalignedInstanceStart());}// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceSize(){return instance_size;}// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize(){returnword_align(unalignedInstanceSize());}
size_t instanceSize(size_t extraBytes){
size_t size =alignedInstanceSize()+ extraBytes;// CF requires all objects be at least 16 bytes.if(size <16) size =16;return size;}};
// 可读可写struct class_rw_t {// Be warned that Symbol ication knows the layout of this structure
uint32_t flags;
uint32_t version;,const class_ro_t *ro;// 指向只读的结构体,存故类初始信息/*
这三个都是二维数组,是可读可写的,包含了类的初始内容,分类的内容
methods 中,存储 methods_list_t --> methods_t
二维数组,methods_list_t --> methods_t
这三个二维数组中的数据有一部分是从 class_ro_t 中合并过来
*/
method_array_t methods;// 方法列表(类对象存放对象方法,元类对象存放实例方法)
property_array_t properties;// 属性列表
protocol_array_t protocols;// 协议列表
Class firstSubclass;
Class nextSiblingClass;// ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
六、class_ro_t 的理解
存储了当前类在编译期就已经确定的属性、方法以及遵循的协议:
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;#ifdef__LP64__
uint32_t reserved;#endifunion{const uint8_t * ivarLayout;
Class nonMetaclass;};
explicit_atomic<constchar*> name;// With ptrauth, this is signed if it points to a small list, but// may be unsigned if it points to a big list.void*baseMethodList;
protocol_list_t * baseProtocols;const ivar_list_t * ivars;const uint8_t * weakIvarLayout;
property_list_t *baseProperties;// ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
七、objc 中向一个 nil 对象发送消息将会发生什么?
如果向一个 nil 对象发送消息,首先在寻找对象的 isa 指针时就是 0 地址返回,所以不会出现任何错误,也不会崩溃。
如果一个方法返回值是一个对象,那么发送给 nil 的消息将返回 0(nil);
如果方法返回值为指针类型,其指针大小为小于或者等于 sizeof(void*) ,float,double,long double 或者 long long 的整型标量,发送给 nil 的消息将返回 0;
如果方法返回值为结构体,发送给 nil 的消息将返回 0,结构体中各个字段的值将都是 0;
如果方法的返回值不是上述提到的几种情况,那么发送给 nil 的消息的返回值将是未定义的。
八、objc 在向一个对象发送消息时,发生了什么?
objc 在向一个对象发送消息时,runtime 会根据对象的 isa 指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,如果一直到根类还没找到,转向拦截调用,执行消息转发机制,一旦找到 ,就去执行它的实现 IMP。