OC Low-level exploration mode

Before exploring alloc’s underlying implementation, we need to master three ways of exploring OC’s underlying implementation:

First, through the sign breakpoint of the way to determine the call of the underlying function

Take exploring alloc as an example:

1. Create a breakpoint on the alloc line and run the program to the breakpoint location

2. Hold down the CTRL key and click Step Info to go directly to the objc_alloc method

3, add objc_alloc symbol breakpoint, we can see objc_alloc implementation method

Ii. Through compilation (commonly used, recommended)

Once we get to the breakpoint, click Debug — Debug Workflow — Always Show Disassembly to go directly to the assembly code and determine the symbol (method/function) currently executed at the bottom level. Add a symbolic breakpoint to see the implementation of objc_alloc

Three, through the known symbol breakpoint, in turn to confirm the unknown symbol

Libobjc.a.dylib ‘+[NSObject alloc]

Explore the underlying implementation of Alloc through objC source code

Objc source code can be found on openSource and downloaded. Open objc source code and search for alloc directly, you can see:

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

+ (id)allocWithZone:(struct _NSZone *)zone {
    return _objc_rootAllocWithZone(self, (malloc_zone_t *)zone);
}
Copy the code

Let’s follow the alloc process step by step directly through breakpoint debugging

The first step is to go to the alloc method and then execute _objc_rootAlloc

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

Next, we come to the callAlloc method

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

In this method, there is a nil check (by argument), followed by a fastPath (! CLS ->ISA()->hasCustomAWZ()) ->hasCustomAWZ()) If so, execute the object’s alloc method via objc_msgSend. Through debugging, I found that I went directly to the _objc_rootAllocWithZone method

id
_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

Go directly to the _class_createInstanceFromZone method

static ALWAYS_INLINE id _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

There are three key methods: CLS ->instanceSize, which calculates how much memory an object needs (there is a 16-byte alignment), CLS ->calloc, which allocates memory for an object CLS ->initInstanceIsa the main function of this method is to associate the OBJ with the CLS via ISA and after going through these processes, our OBJ is alloc out.

Note: There is a branch process that needs to be added later, that is, CLS implements the process of allocWithZone method in callAlloc method.