欢迎关注
最酷最in的云资讯

objc_object解读

Objective-C是面向对象的语言.面向对象语言有一句话说:”万物皆对象”,这个”对象”从哪里来呢?下面从Runtime源码实现来进一步查看.

一. objc_object声明相关

首先我们先看runtime.h文件,这个文件相当于Runtime对外部提供的接口文件.包含方法,成员变量,分类,属性等结构声明,也包含了objc_class的完整声明.当我们使用Xcode创建一个类的时候一般都是调用的这里.

/**Runtime对外提供的接口,包含方法,成员变量,分类,属性等结构声明,也包含了objc_class的完整声明**//* Types */#if !OBJC_TYPES_DEFINED/// 表示一个类中的方法/// An opaque type that represents a method in a class definition.typedef struct objc_method *Method;/// 表示类中的一个成员变量/// An opaque type that represents an instance variable.typedef struct objc_ivar *Ivar;/// 表示一个分类/// An opaque type that represents a category.typedef struct objc_category *Category;/// 表示一个属性/// An opaque type that represents an Objective-C declared property.typedef struct objc_property *objc_property_t;/// 类的声明结构struct objc_class {Class _Nonnull isa OBJC_ISA_AVAILABILITY;#if !__OBJC2__Class _Nullable super_class OBJC2_UNAVAILABLE;const char * _Nonnull name OBJC2_UNAVAILABLE;long version OBJC2_UNAVAILABLE;long info OBJC2_UNAVAILABLE;long instance_size OBJC2_UNAVAILABLE;struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;#endif} OBJC2_UNAVAILABLE;/* Use `Class` instead of `struct objc_class *` */

可以看到objc_class的结构声明中有isa指针,这个指针是Class类型,然后我们顺藤摸瓜,继续查找Class的定义来源.然后找到了objc-private.h文件,进入文件后我们看到结构体objc_class和objc_object的不完整声明如下:

// MARK: - objc_class 和 objc_object 不完整声明struct objc_class;struct objc_object;

接着是用typedef 将这两个类型取了两个熟悉的名字:Class指针和id指针:

// MARK: - 将objc_class类型取名为Class指针类型;将objc_object类型取名为id指针类型typedef struct objc_class *Class;typedef struct objc_object *id;

往下就是isa的声明union(联合体),isa_t中有两个初始化函数,两个成员变量,cls和bits,还有一个结构体成员.其中在不同的os平台,有不同的声明.

# 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<= 2 || (__arm64__ && !__LP64__)// armv7k or arm64_32# define ISA_INDEX_IS_NPI_BIT 0# define ISA_INDEX_IS_NPI_MASK 0x00000001# define ISA_INDEX_MASK 0x0001FFFC# define ISA_INDEX_SHIFT 2# define ISA_INDEX_BITS 15# define ISA_INDEX_COUNT (1 << ISA_INDEX_BITS)# define ISA_INDEX_MAGIC_MASK 0x001E0001# define ISA_INDEX_MAGIC_VALUE 0x001C0001# define ISA_BITFIELD \uintptr_t nonpointer : 1; \uintptr_t has_assoc : 1; \uintptr_t indexcls : 15; \uintptr_t magic : 4; \uintptr_t has_cxx_dtor : 1; \uintptr_t weakly_referenced : 1; \uintptr_t deallocating : 1; \uintptr_t has_sidetable_rc : 1; \uintptr_t extra_rc : 7# define RC_ONE (1ULL<<25)# define RC_HALF (1ULL<<6)

nonpointer: 标记此isa是否是tagged pointer优化后的isa.占用1bit.值为1说明是优化后的isa.具体参考链接,tagged pointer是对实例对象的优化,默认是true,并且是isClass的判断,这是我看源码的理解,不对请指正

has_assoc:标记object是否有关联对象,没有,释放更快

has_cxx_dtor:标记是否有西沟函数,没有,释放更快

shiftcls:类对象(Class,meta-Class对象)内存地址信息

magic:标记object是否初始化完成

weakly_refrenced:标记object是否有weak指针指向它

deallocating:标记object是否正在释放

has_sidetable_rc:标记object的extra_rc位数能否存的下object的引用计数,存不下即has_sidetable_rc=1,存在全局的SideTable里面

extra_rc:存储object的引用计数,存不下,存在全局的SideTable里面

下面是object的完整声明:

// MARK: - object的完整声明struct objc_object {private:// 私有成员变量: isa指针isa_t isa;// 公有函数public:// 通过这个函数获取不支持tagged pointer的类指针// ISA() assumes this is NOT a tagged pointer objectClass ISA();// 通过这个函数获取支持tagged pointer的类指针// getIsa() allows this to be a tagged pointer objectClass getIsa();// 以下几个函数是isa的初始化函数// initIsa()用来初始化一个新的对象的isa// initIsa() should be used to init the isa of new objects only.// changeIsa 修改一个对象的isa// If this object already has an isa, use changeIsa() for correctness.// initInstanceIsa()用来初始化一个实例对象的isa// initInstanceIsa(): objects with no custom RR/AWZ// initClassIsa()用来初始化一个类对象的isa// initClassIsa(): class objects// initProtocolIsa()用来初始化一个protocol的isa// initProtocolIsa(): protocol objects// initIsa()还用来初始化其它类型对象的isa// initIsa(): other objectsvoid initIsa(Class cls /*nonpointer=false*/);void initClassIsa(Class cls /*nonpointer=maybe*/);void initProtocolIsa(Class cls /*nonpointer=maybe*/);void initInstanceIsa(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);// tagged pointer 相关bool hasNonpointerIsa();bool isTaggedPointer();bool isBasicTaggedPointer();bool isExtTaggedPointer();// 是否是Classbool isClass();// 关联对象相关// object may have associated objects?bool hasAssociatedObjects();void setHasAssociatedObjects();// weak指针相关// object may be weakly referenced?bool isWeaklyReferenced();void setWeaklyReferenced_nolock();// 对象是否有析构函数// object may have -.cxx_destruct implementation?bool hasCxxDtor();// retain 和 release 操作对象的引用计数 声明函数// Optimized calls to retain/release methodsid retain();void release();id autorelease();// retain 和 release 操作对象的引用计数 实现函数// Implementations of retain/release methodsid rootRetain();bool rootRelease();id rootAutorelease();bool rootTryRetain();bool rootReleaseShouldDealloc();uintptr_t rootRetainCount();// 释放销毁对象相关// Implementation of dealloc methodsbool rootIsDeallocating();void clearDeallocating();void rootDealloc();// 私有函数 上面一些公有函数的调用函数private:void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor);// Slow paths for inline controlid rootAutorelease2();bool overrelease_error();#if SUPPORT_NONPOINTER_ISA// Unified retain count manipulation for nonpointer isaid rootRetain(bool tryRetain, bool handleOverflow);bool rootRelease(bool performDealloc, bool handleUnderflow);id rootRetain_overflow(bool tryRetain);bool rootRelease_underflow(bool performDealloc);void clearDeallocating_slow();// Side table retain count overflow for nonpointer isavoid sidetable_lock();void sidetable_unlock();void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);bool sidetable_addExtraRC_nolock(size_t delta_rc);size_t sidetable_subExtraRC_nolock(size_t delta_rc);size_t sidetable_getExtraRC_nolock();#endif// Side-table-only retain countbool sidetable_isDeallocating();void sidetable_clearDeallocating();bool sidetable_isWeaklyReferenced();void sidetable_setWeaklyReferenced_nolock();id sidetable_retain();id sidetable_retain_slow(SideTable& table);uintptr_t sidetable_release(bool performDealloc = true);uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true);bool sidetable_tryRetain();uintptr_t sidetable_retainCount();#if DEBUGbool sidetable_present();#endif};

以上就是objc_object的具体声明结构,里面有许多值得深究的问题,也是接下来会继续关注的问题.

二.实例对象的初始化

1.alloc

下面我们来看一个对象的实例化过程:

Class newClass = objc_allocateClassPair(objc_getClass("NSObject"), "newClass", 0);objc_registerClassPair(newClass);id newObject = [[newClass alloc]init];NSLog(@"%s",class_getName([newObject class]));NSLog(@"Hello, World!");

上面代码时创建一个newClass类,并且用这个新类实例化一个newObject对象.查看一下alloc方法和init方法的调用栈,其中省略了中间过程:

id _objc_rootAlloc(Class cls)└── static id callAlloc(Class cls, bool checkNil, bool allocWithZone=false)└── id class_createInstance(Class cls, size_t extraBytes)└── id _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, bool cxxConstruct, size_t *outAllocatedSize)├── size_t instanceSize(size_t extraBytes)├── void *calloc(size_t, size_t)└── inline void objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)

其中NSObject.mm中对alloc的实现如下:

+ (id)alloc {return _objc_rootAlloc(self);}

这里面调用了一个私有函数,返回一个id类型(objc_object)如下:

id_objc_rootAlloc(Class cls){return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);}

NSObject.mm对callAlloc()实现:

// Call [cls alloc] or [cls allocWithZone:nil], with appropriate// shortcutting optimizations.static ALWAYS_INLINE idcallAlloc(Class cls, bool checkNil, bool allocWithZone=false){if (slowpath(checkNil && !cls)) return nil;#if __OBJC2__if (fastpath(!cls->ISA()->hasCustomAWZ())) {// No alloc/allocWithZone implementation. Go straight to the allocator.// fixme store hasCustomAWZ in the non-meta class and// add it to canAllocFast's summaryif (fastpath(cls->canAllocFast())) {// No ctors, raw isa, etc. Go straight to the metal.bool dtor = cls->hasCxxDtor();id obj = (id)calloc(1, cls->bits.fastInstanceSize());if (slowpath(!obj)) return callBadAllocHandler(cls);obj->initInstanceIsa(cls, dtor);return obj;}else {// Has ctor or raw isa or something. Use the slower path.id obj = class_createInstance(cls, 0);if (slowpath(!obj)) return callBadAllocHandler(cls);return obj;}}#endif// No shortcuts available.if (allocWithZone) return [cls allocWithZone:nil];return [cls alloc];}

其中有个class_createInstance()函数,这函数中会调用_class_createInstanceFromZone()函数:

static __attribute__((always_inline))

id

_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,

bool cxxConstruct = true,

size_t *outAllocatedSize

static __attribute__((always_inline))id_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,bool cxxConstruct = true,size_t *outAllocatedSize = nil){if (!cls) return nil;assert(cls->isRealized());// Read class's info bits all at once for performancebool hasCxxCtor = cls->hasCxxCtor();bool hasCxxDtor = cls->hasCxxDtor();bool fast = cls->canAllocNonpointer();size_t size = cls->instanceSize(extraBytes);if (outAllocatedSize) *outAllocatedSize = size;id obj;if (!zone && fast) {obj = (id)calloc(1, size);if (!obj) return nil;obj->initInstanceIsa(cls, hasCxxDtor);}else {if (zone) {obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);} else {obj = (id)calloc(1, size);}if (!obj) return nil;// Use raw pointer isa on the assumption that they might be// doing something weird with the zone or RR.obj->initIsa(cls);}if (cxxConstruct && hasCxxCtor) {obj = _objc_constructOrFree(obj, cls);}return obj;}

这里面有:1)instanceSize()是给对象分配内存空间:

size_t instanceSize(size_t extraBytes) {size_t size = alignedInstanceSize() + extraBytes;if (size ro->instanceSize;}

2)initIsa()初始化isa指针

inline voidobjc_object::initIsa(Class cls){initIsa(cls, false, false);}inline voidobjc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor){assert(!isTaggedPointer());// 不是tagged pointerif (!nonpointer) {isa.cls = cls;} else {assert(!DisableNonpointerIsa);assert(!cls->instancesRequireRawIsa());isa_t newisa(0);#if SUPPORT_INDEXED_ISAassert(cls->classArrayIndex() > 0);newisa.bits = ISA_INDEX_MAGIC_VALUE;// isa.magic is part of ISA_MAGIC_VALUE// isa.nonpointer is part of ISA_MAGIC_VALUEnewisa.has_cxx_dtor = hasCxxDtor;newisa.indexcls = (uintptr_t)cls->classArrayIndex();#elsenewisa.bits = ISA_MAGIC_VALUE;// isa.magic is part of ISA_MAGIC_VALUE// isa.nonpointer is part of ISA_MAGIC_VALUEnewisa.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 instantiationisa = newisa;}}

2.init

init()函数调用栈很简单,只是调用了_objc_rootInit()私有函数,并返回对象本身

- (id)init {return _objc_rootInit(self);}id_objc_rootInit(id obj){// In practice, it will be hard to rely on this function.// Many classes do not properly chain -init calls.return obj;}

对象的初始化过程可以总结为分配内存空间并且初始化isa_t结构的过程.

参考文献:

https://blog.devtang.com/2014/05/30/understand-tagged-pointer/

作者:偶尔登南山

链接:https://www.swifty.cc/p/da68505cc383

赞(0) 打赏
未经允许不得转载:云微资讯 » objc_object解读
分享到: 更多 (0)

云微资讯 科技新媒体资讯平台

关于我们联系我们

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏