alloc 方法作了什麼?html
// 由源碼可知
+ (id)alloc {
return _objc_rootAlloc(self);
}
// 接着👇
id _objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
// 接着👇
static ALWAYS_INLINE id callAlloc(Class cls, bool checkNil, bool allocWithZone=false) {
if (checkNil && !cls) return nil;
#if __OBJC2__
// 首先判斷當前類是否 hasCustomAWZ ,該方法定義以下
/** bool hasCustomAWZ() { return ! bits.hasDefaultAWZ(); } bool hasDefaultAWZ() { return data()->flags & RW_HAS_DEFAULT_AWZ; } 而 RW_HAS_DEFAULT_AWZ 的定義以下:表示是否擁有默認建立方法 // class or superclass has default alloc/allocWithZone: implementation // Note this is is stored in the metaclass. #define RW_HAS_DEFAULT_AWZ (1<<16) */
// 無默認建立方法
if (! 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 summary
if (cls->canAllocFast()) {
// No ctors, raw isa, etc. Go straight to the metal.
// 判斷是否有析構函數
bool dtor = cls->hasCxxDtor();
// 直接初始化,而且置爲 0
id obj = (id)calloc(1, cls->bits.fastInstanceSize());
// 建立失敗,則被 badHandler 捕獲
if (!obj) return callBadAllocHandler(cls);
// 而後初始化
obj->initInstanceIsa(cls, dtor);
return obj;
} else {
// Has ctor or raw isa or something. Use the slower path.
/** // 若是沒法進行快速建立,則直接在 zone 中分配一塊空間來建立 id class_createInstance(Class cls, size_t extraBytes) { return _class_createInstanceFromZone(cls, extraBytes, nil); } */
id obj = class_createInstance(cls, 0);
if (!obj) return callBadAllocHandler(cls);
return obj;
}
}
#endif
// No shortcuts available.
if (allocWithZone) return [cls allocWithZone:nil];
return [cls alloc];
}
複製代碼
最終都調用了 _class_createInstanceFromZone
方法objective-c
// 如今咱們來看一下這個方法
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 performance
// 判斷是否有析構函數
bool 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) {
// 若是 zone 爲空 而且能夠快速構造,則直接使用 calloc 函數快速構造一個 size 大小的位置
obj = (id)calloc(1, size);
if (!obj) return nil;
// 初始化數據
obj->initInstanceIsa(cls, hasCxxDtor);
}
else {
// 若是不支持快速構造而且有 zone,則直接在 zone 上分配一個 size 大小的存儲空間
if (zone) {
obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
// 若是不支持快速構造而且無 zone,則直接使用 calloc 分配一個 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;
}
複製代碼
而咱們以後,須要調用 init 方法,來實現對象真正的完成出生過程swift
- (id)init {
return _objc_rootInit(self);
}
_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;
}
複製代碼
至此,對象的出生真正完成併發
首先定義以下類app
#import <Foundation/Foundation.h>
@interface LYObject : NSObject
@property (nonatomic, strong) NSString *name;
- (void)study;
+ (void)sleep;
@end
@implementation LYObject
- (void)study {
NSLog(@"studying");
}
+ (void)sleep {
NSLog(@"sleeping");
}
@end
複製代碼
而後在 viewController 中調用它ide
- (void)testSuperClass {
LYObject *obj = [[LYObject alloc] init];
NSLog(@"class - %@", [obj class]);
NSLog(@"superClass - %@", [obj superclass]);
NSLog(@"metaClass -- %@", object_getClass([obj class]));
NSLog(@"metaClass's metaClass -- %@", object_getClass(object_getClass([obj class])));
NSLog(@"metaClass's superClass -- %@", [object_getClass([obj class]) superclass]);
// 打印結果
/**
2017-12-28 21:16:43.972104+0800 RuntimeTest[60981:11200702] class - LYObject
2017-12-28 21:16:43.972300+0800 RuntimeTest[60981:11200702] superClass - NSObject
2017-12-28 21:16:43.972417+0800 RuntimeTest[60981:11200702] metaClass -- LYObject
2017-12-28 21:16:43.972530+0800 RuntimeTest[60981:11200702] metaClass's metaClass -- NSObject
2017-12-28 21:16:43.972626+0800 RuntimeTest[60981:11200702] metaClass's superClass -- NSObject
*/
}
- (void)testPoiter {
Class currentClass = [LYObject class];
for (int i = 1; i < 5; i++)
{
NSLog(@"Following the isa pointer %d times gives %p %@", i, currentClass,currentClass);
currentClass = object_getClass(currentClass);
}
NSLog(@"NSObject's class is %p", [NSObject class]);
NSLog(@"NSObject's meta class is %p", object_getClass([NSObject class]));
NSLog(@"NSObject's meta class's meta class is %p", object_getClass(object_getClass([NSObject class])));
/**
2017-12-28 21:18:58.430792+0800 RuntimeTest[61004:11204340] Following the isa pointer 1 times gives 0x1036f3060 LYObject
// 代表此時指向 LYObject 的類
2017-12-28 21:18:58.430971+0800 RuntimeTest[61004:11204340] Following the isa pointer 2 times gives 0x1036f3038 LYObject
// 此時指向 LYObject 的 meta class
2017-12-28 21:18:58.431090+0800 RuntimeTest[61004:11204340] Following the isa pointer 3 times gives 0x1046aae58 NSObject
// 此時指向 LYObject 的 meta class 的 superClass
2017-12-28 21:18:58.431185+0800 RuntimeTest[61004:11204340] Following the isa pointer 4 times gives 0x1046aae58 NSObject
// 表面實際上 NSObject 類的 meta class 指針指向本身
2017-12-28 21:18:58.431277+0800 RuntimeTest[61004:11204340] NSObject's class is 0x1046aaea8
2017-12-28 21:18:58.431501+0800 RuntimeTest[61004:11204340] NSObject's meta class is 0x1046aae58
2017-12-28 21:18:58.431793+0800 RuntimeTest[61004:11204340] NSObject's meta class's meta class is 0x1046aae58
*/
}
複製代碼
由這兩個方法能夠看出,實際上 LYObject 對象的 class 爲 LYObject, LYObject 類的 class(即metaClass)爲 LYObject, 可是 LYObject 的 metaClass 的 superClass 爲 NSObject,如圖函數
咱們進一步能夠看到,在黑框中的兩個 class 其實是一對 classPair,在 Runtime 的代碼定義中以下:源碼分析
/** @param superclass 表示這個方法首先指明新建 class 的 superclass,若是新建的 class 是一個 rootclass,則直接傳遞 nil @param name 表示新建立的 class 的 name, 這個 name 的修飾符爲 copy @param extraBytes 表示 The number of bytes to allocate for indexed ivars at the end of the class and metaclass objects. This should usually be \c 0. 一般爲 0 建立一對新的 class pair 的步驟, 首先,調用 objc_allocateClassPair 方法 而後,調用 class_addMethod or class_addIvars 來給當前的類添加編譯時的屬性 而後,調用 objc_registerClassPair 來註冊這個 class ,此時這個新的 class 就準備好了! 最後,在 Runtime 時期,動態的爲類添加 實例變量和 實例方法,而類方法應該被添加到 metaclass 中 */
Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes) {
Class cls, meta;
rwlock_writer_t lock(runtimeLock);
// Fail if the class name is in use.
// Fail if the superclass isn't kosher.
if (getClass(name) || !verifySuperclass(superclass, true/*rootOK*/)) {
return nil;
}
// Allocate new classes.
cls = alloc_class_for_subclass(superclass, extraBytes);
meta = alloc_class_for_subclass(superclass, extraBytes);
// fixme mangle the name if it looks swift-y?
objc_initializeClassPair_internal(superclass, name, cls, meta);
return cls;
}
// 在上述方法中給 cls 和 meta 指針賦值時, 調用了 alloc_class_for_subclass 方法,這個方法實際上就是建立了一個類的地址空間給它使用。
static Class alloc_class_for_subclass(Class supercls, size_t extraBytes) {
if (!supercls || !supercls->isSwift()) {
return _calloc_class(sizeof(objc_class) + extraBytes);
}
}
// 也調用了另外一個方法 objc_initializeClassPair_internal, 在這個方法中👇
// &UnsetLayout is the default ivar layout during class construction
static const uint8_t UnsetLayout = 0;
static void objc_initializeClassPair_internal(Class superclass, const char *name, Class cls, Class meta) {
runtimeLock.assertWriting();
// 首先聲明兩個儲存類信息的指針
class_ro_t *cls_ro_w, *meta_ro_w;
// 爲 class_rw_t 結構體建立控件,而後初始化爲 0
cls->setData((class_rw_t *)calloc(sizeof(class_rw_t), 1));
meta->setData((class_rw_t *)calloc(sizeof(class_rw_t), 1));
cls_ro_w = (class_ro_t *)calloc(sizeof(class_ro_t), 1);
meta_ro_w = (class_ro_t *)calloc(sizeof(class_ro_t), 1);
// 而後使 data() 返回的 class_rw_t 指針的 ro 變量指向剛剛聲明的兩個指針 cls_ro_w 和 meta_ro_w
cls->data()->ro = cls_ro_w;
meta->data()->ro = meta_ro_w;
// 接着設置初始化信息
/** // class allocated but not yet registered #define RW_CONSTRUCTING (1<<26) // class_rw_t->ro is heap copy of class_ro_t #define RW_COPIED_RO (1<<27) // Values for class_rw_t->flags // These are not emitted by the compiler and are never used in class_ro_t. // Their presence should be considered in future ABI versions. // class_t->data is class_rw_t, not class_ro_t #define RW_REALIZED (1<<31) // available for use // #define RW_20 (1<<20) // class has started realizing but not yet completed it #define RW_REALIZING (1<<19) */
cls->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;
meta->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;
// 設置 version, 7 表示 meta class
cls->data()->version = 0;
meta->data()->version = 7;
// 設置 flag RO_META 表示 meta class
cls_ro_w->flags = 0;
meta_ro_w->flags = RO_META;
// 若是都沒有 superclass, 則爲 rootclass
if (!superclass) {
cls_ro_w->flags |= RO_ROOT;
meta_ro_w->flags |= RO_ROOT;
}
if (superclass) {
cls_ro_w->instanceStart = superclass->unalignedInstanceSize();
meta_ro_w->instanceStart = superclass->ISA()->unalignedInstanceSize();
cls->setInstanceSize(cls_ro_w->instanceStart);
meta->setInstanceSize(meta_ro_w->instanceStart);
} else {
cls_ro_w->instanceStart = 0;
meta_ro_w->instanceStart = (uint32_t)sizeof(objc_class);
cls->setInstanceSize((uint32_t)sizeof(id)); // just an isa
meta->setInstanceSize(meta_ro_w->instanceStart);
}
cls_ro_w->name = strdupIfMutable(name);
meta_ro_w->name = strdupIfMutable(name);
cls_ro_w->ivarLayout = &UnsetLayout;
cls_ro_w->weakIvarLayout = &UnsetLayout;
meta->chooseClassArrayIndex();
cls->chooseClassArrayIndex();
// Connect to superclasses and metaclasses
cls->initClassIsa(meta);
if (superclass) {
meta->initClassIsa(superclass->ISA()->ISA());
cls->superclass = superclass;
meta->superclass = superclass->ISA();
addSubclass(superclass, cls);
addSubclass(superclass->ISA(), meta);
} else {
複製代碼
當咱們對一個對象發送 dealloc 消息時優化
// Replaced by NSZombies
- (void)dealloc {
_objc_rootDealloc(self);
}
// 內部調用
void
_objc_rootDealloc(id obj)
{
assert(obj);
obj->rootDealloc();
}
inline void
objc_object::rootDealloc()
{
if (isTaggedPointer()) return; // fixme necessary?
/** nonpointer表明是否開啓isa指針優化。 weakly_referenced表明對象被指向或者曾經指向一個 ARC 的弱變量。 has_assoc表明對象含有或者曾經含有關聯引用。 has_cxx_dtor以前提到過了,是析構器。 has_sidetable_rc判斷該對象的引用計數是否過大。 */
if (fastpath(isa.nonpointer &&
!isa.weakly_referenced &&
!isa.has_assoc &&
!isa.has_cxx_dtor &&
!isa.has_sidetable_rc))
{
assert(!sidetable_present());
free(this);
}
else {
object_dispose((id)this);
}
}
// 又調用
id object_dispose(id obj) {
if (!obj) return nil;
objc_destructInstance(obj);
free(obj);
return nil;
}
/*********************************************************************** * objc_destructInstance * Destroys an instance without freeing memory. * Calls C++ destructors. * Calls ARC ivar cleanup. * Removes associative references. * Returns `obj`. Does nothing if `obj` is nil. **********************************************************************/
void *objc_destructInstance(id obj) {
if (obj) {
// Read all of the flags at once for performance.
bool cxx = obj->hasCxxDtor();
bool assoc = obj->hasAssociatedObjects();
// This order is important.
// 判斷是否有析構器,若是有,就直接調用👇方法
if (cxx) object_cxxDestruct(obj);
if (assoc) _object_remove_assocations(obj);
obj->clearDeallocating();
}
return obj;
}
複製代碼
當調用 object_cxxDestruct 方法時,後續調用以下:ui
/*********************************************************************** * object_cxxDestruct. * Call C++ destructors on obj, if any. * Uses methodListLock and cacheUpdateLock. The caller must hold neither. **********************************************************************/
void object_cxxDestruct(id obj) {
if (!obj) return;
if (obj->isTaggedPointer()) return;
object_cxxDestructFromClass(obj, obj->ISA());
}
/*********************************************************************** * object_cxxDestructFromClass. * Call C++ destructors on obj, starting with cls's * dtor method (if any) followed by superclasses' dtors (if any), * stopping at cls's dtor (if any). * Uses methodListLock and cacheUpdateLock. The caller must hold neither. **********************************************************************/
static void object_cxxDestructFromClass(id obj, Class cls) {
void (*dtor)(id);
// Call cls's dtor first, then superclasses's dtors.
for ( ; cls; cls = cls->superclass) {
if (!cls->hasCxxDtor()) return;
dtor = (void(*)(id))
lookupMethodInClassAndLoadCache(cls, SEL_cxx_destruct);
if (dtor != (void(*)(id))_objc_msgForward_impcache) {
if (PrintCxxCtors) {
_objc_inform("CXX: calling C++ destructors for class %s",
cls->nameForLogging());
}
(*dtor)(obj);
}
}
}
/*********************************************************************** * object_cxxDestructFromClass. * Call C++ destructors on obj, starting with cls's * dtor method (if any) followed by superclasses' dtors (if any), * stopping at cls's dtor (if any). * Uses methodListLock and cacheUpdateLock. The caller must hold neither. **********************************************************************/
static void object_cxxDestructFromClass(id obj, Class cls) {
void (*dtor)(id);
// Call cls's dtor first, then superclasses's dtors.
for ( ; cls; cls = cls->superclass) {
if (!cls->hasCxxDtor()) return;
dtor = (void(*)(id))
// 從子類開始沿着繼承鏈一直找到父類,向上搜尋 SEL_cxx_destruct 這個selector,找到函數實現(void (*)(id)(函數指針)並執行。實現垃圾回收
lookupMethodInClassAndLoadCache(cls, SEL_cxx_destruct);
if (dtor != (void(*)(id))_objc_msgForward_impcache) {
if (PrintCxxCtors) {
_objc_inform("CXX: calling C++ destructors for class %s",
cls->nameForLogging());
}
(*dtor)(obj);
}
}
}
複製代碼
當調用 _object_remove_assocations 方法時,後續調用以下:
void _object_remove_assocations(id object) {
vector< ObjcAssociation,ObjcAllocator<ObjcAssociation> > elements;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
if (associations.size() == 0) return;
disguised_ptr_t disguised_object = DISGUISE(object);
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
// copy all of the associations that need to be removed.
ObjectAssociationMap *refs = i->second;
for (ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) {
elements.push_back(j->second);
}
// remove the secondary table.
delete refs;
associations.erase(i);
}
}
// the calls to releaseValue() happen outside of the lock.
for_each(elements.begin(), elements.end(), ReleaseValue());
}
複製代碼
至此,對象被銷燬