Alloc is one of the most frequently used system methods for an iOS developer. Have you ever wondered what it is and how it is implemented? This article will explore the underlying principle;

The preparatory work

For low-level exploration, of course, you need the underlying source of OC. Apple is also giving developers some support in this area. We can through opensource.apple.com or download opensource.apple.com/tarballs/ to apple’s open source code; (ObjC4-824 is the latest version, it is too new to run, you can use the old version, it depends on your machine, I use objC4-818)

Cooci can also be used to compile the source code

Began to explore

An alloC underlying flow chart on the line (only with limited drawing skills)

To explore the method of

Add symbol breakpoint alloc –> libobjc.a. dylib ‘_objc_rootalloc:

The first breakpoint is on the alloc line, and the sign breakpoint alloc (needs to be set to disable otherwise it will break in NSObject’s alloc)Then run the Commond + setp into debugging command to obtain the command

Add symbolic breakpoints from assembly: objc_alloc

Xcode–>Debug–>Debug Workflow–>Always Show DisassemblyThen control + step into debugging shows that objc_alloc is the next call to the functionAdd objc_alloc symbol breakpointThen run it again to get the next function called _objc_rootAllocWithZone and set it to a symbolic breakpoint. The alloC operation flow can be obtained by following this step

The source code is as follows:

1.alloc

    return _objc_rootAlloc(self);
}
Copy the code

3.callAlloc

callAlloc(Class cls, bool checkNil, bool allocWithZone=false) { #if __OBJC2__ if (slowpath(checkNil && ! cls)) return nil; if (fastpath(! cls->ISA()->hasCustomAWZ())) { return _objc_rootAllocWithZone(cls, nil); } #endif // No shortcuts available. if (allocWithZone) { return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil); } return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc)); }Copy the code

2._objc_rootAlloc

_objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
Copy the code

4._objc_rootAllocWithZone

_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone __unused)
{
    // allocWithZone under __OBJC2__ ignores the zone parameter
    return _class_createInstanceFromZone(cls, 0, nil,
                                         OBJECT_CONSTRUCT_CALL_BADALLOC);
}
Copy the code

5._class_createInstanceFromZone

_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, int construct_flags = OBJECT_CONSTRUCT_NONE, bool cxxConstruct = true, size_t *outAllocatedSize = nil) { ASSERT(cls->isRealized()); // Read class's info bits all at once for performance bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor(); bool hasCxxDtor = cls->hasCxxDtor(); bool fast = cls->canAllocNonpointer(); size_t size; size = cls->instanceSize(extraBytes); if (outAllocatedSize) *outAllocatedSize = size; id obj; if (zone) { obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size); } else { obj = (id)calloc(1, size); } if (slowpath(! obj)) { if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) { return _objc_callBadAllocHandler(cls); } return nil; } if (! zone && fast) { obj->initInstanceIsa(cls, hasCxxDtor); } else { // Use raw pointer isa on the assumption that they might be // doing something weird with the zone or RR. obj->initIsa(cls); } if (fastpath(! hasCxxCtor)) { return obj; } construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE; return object_cxxConstructFromClass(obj, cls, construct_flags); }Copy the code