Fundamentals 11 min read

Understanding the Object Creation Process in Objective‑C

This article explains how Objective‑C creates objects by detailing the two creation methods, the internal alloc and init implementations, the callAlloc workflow, memory allocation, and the final binding of the isa pointer, with full source code excerpts for each step.

JD Retail Technology
JD Retail Technology
JD Retail Technology
Understanding the Object Creation Process in Objective‑C

In ordinary Objective‑C development we use [[Class alloc] init] or [Class new] to create objects, but the underlying process involves many runtime functions that are rarely examined.

Object creation methods

[[Class alloc] init]

[Class new]

The alloc method is implemented as:

+ (id)alloc {
    return _objc_rootAlloc(self);
}
// Base class implementation of +alloc. Calls [cls allocWithZone:nil].

The init path for the root class is:

+ (id)init {
    return (id)self;
}
- (id)init {
    return _objc_rootInit(self);
}
id _objc_rootInit(id obj) {
    // Many classes do not properly chain -init calls.
    return obj;
}

The new method simply combines alloc and init :

+ (id)new {
    return [callAlloc(self, false/*checkNil*/ ) init];
}
- (id)init {
    return _objc_rootInit(self);
}

When alloc is invoked, the runtime calls objc_alloc , which forwards to callAlloc :

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

callAlloc performs several checks and then either allocates memory directly or falls back to class_createInstance . Important macros used are:

#define fastpath(x) (__builtin_expect(bool(x), 1))
#define slowpath(x) (__builtin_expect(bool(x), 0))

The function hasCustomAWZ determines whether the class implements its own allocWithZone: method:

bool hasCustomAWZ() {
    return !bits.hasDefaultAWZ();
}
bool hasDefaultAWZ() {
    return data()->flags & RW_HAS_DEFAULT_AWZ;
}

If fast allocation is possible, callAlloc uses calloc to obtain raw memory:

id obj = (id)calloc(1, cls->bits.fastInstanceSize());
obj->initInstanceIsa(cls, dtor);
return obj;

The size of the memory block is calculated by instanceSize :

size_t instanceSize(size_t extraBytes) {
    size_t size = alignedInstanceSize() + extraBytes;
    if (size < 16) size = 16;
    return size;
}
static inline uint32_t word_align(uint32_t x) { return (x + WORD_MASK) & ~WORD_MASK; }

After memory is allocated, initInstanceIsa links the newly created object with its class by initializing the isa pointer:

inline void objc_object::initInstanceIsa(Class cls, bool hasCxxDtor) {
    initIsa(cls, true, hasCxxDtor);
}
inline void objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) {
    if (!nonpointer) {
        isa.cls = cls;
    } else {
        isa_t newisa(0);
        #if SUPPORT_INDEXED_ISA
        newisa.bits = ISA_INDEX_MAGIC_VALUE;
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.indexcls = (uintptr_t)cls->classArrayIndex();
        #else
        newisa.bits = ISA_MAGIC_VALUE;
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.shiftcls = (uintptr_t)cls >> 3;
        #endif
        isa = newisa;
    }
}

In summary, the object creation flow consists of calculating the required memory size, allocating it with calloc , and finally initializing the isa pointer to bind the object to its class.

runtimeObject CreationObjective-CMemory Allocationallocinit
JD Retail Technology
Written by

JD Retail Technology

Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.