Creation of the 1.0 OC object

Alloc, init, and new allocate memory for initializing objects. 2, Alloc int new what is the difference? Is the memory the same? 3. How much memory does an object occupy? 4. What is the object creation process?

Do a demo test:

    LGPerson *p1 = [LGPerson alloc];
    LGPerson *p2 = [LGPerson new];
    LGPerson *p3 = [p1 init];
    LGPerson *p4 = [p1 init];
    
    NSLog(@"%@-%p-%p-size:%ld",p1,p1,&p1,sizeof(p1));
    NSLog(@"%@-%p-%p-size:%ld",p2,p2,&p2,sizeof(p2));
    NSLog(@"%@-%p-%p-size:%ld",p3,p3,&p3,sizeof(p3));
    NSLog(@"%@-%p-%p-size:%ld",p4,p4,&p4,sizeof(p4));
Copy the code

The following output is displayed:

<LGPerson: 0x283a848e0>-0x283a848e0-0x16fc11af8-size:8
<LGPerson: 0x283a848c0>-0x283a848c0-0x16fc11af0-size:8
<LGPerson: 0x283a848e0>-0x283a848e0-0x16fc11ae8-size:8
<LGPerson: 0x283a848e0>-0x283a848e0-0x16fc11ae0-size:8
Copy the code

Both alloc and new initialize the object and allocate memory. The first address of the pointer to the object created by alloc is 0x281abc3B0, and the first address of the pointer to the object created by new is 0x281abc3C0. Pointer is a variable to store address. 0x16EE95AF8, 0x16EE95AF0, 0x16EE95AE8, 0x16EE95AE8, 0x16EE95B0 are the addresses of four pointer variables

Alloc /int refers to the same memory space. New creates a new memory space.

So how do alloc and new actually create objects and allocate memory? Simple and crude point directly on the source breakpoint debugging, source address: objC4, in this thank Cooci teacher to provide adjustable source ~~

2.0 Alloc execution process

Let’s start with a few important pieces of source code

2.0.1 callAlloc

static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false){#if __OBJC2__
    if(slowpath(checkNil && ! cls))return nil;
    // If there is a custom allocWithZone (hasCustomAWZ) most likely to use this method
    if(fastpath(! cls->ISA()->hasCustomAWZ())) {return _objc_rootAllocWithZone(cls, nil);
    }
#endif

    //allocWithZone==true
    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

Analysis: The _objc_rootAllocWithZone method is entered according to the callAlloc parameter

2.0.2 _class_createInstanceFromZone

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;
    // In iOS, bytes are 8 aligned by themselves, while memory is 16 aligned, so anything less than 16 bytes will be completed
    size = cls->instanceSize(extraBytes);
    if (outAllocatedSize) *outAllocatedSize = size;

    id obj;
    // Open up memory space
    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) {// The associated object isa
        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

Analysis: first calculate the memory space required by the object, the memory opening is 16 bytes for alignment, then calloc open up memory, and finally associate the object ISA.

The 2.0.3 instanceSize

  inline size_t instanceSize(size_t extraBytes) const {
        if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
            return cache.fastInstanceSize(extraBytes);
        }

        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
        if (size < 16) size = 16;  
        return size;
    }
Copy the code

Analysis: Word_align, align16, these two calculations determine ios memory alignment by 16 bytes, byte alignment by 8 bytes. That means creating an object requires at least 16 bytes of memory

2.0.3 Flow chart analysis

This figure shows the execution flow of the alloC creation object.

2.0.4 Calloc Is executed twice

During breakpoint debugging, calloc was executed twice? Through debugging and reference, it is found that the system will point alloc to objc_alloc through LLVM function method, and then call callAlloc(CLS, true, false) in objC_alloc. Finally, objc_msgSend forwards alloc. Execute the alloc method.

static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false){#if __OB
     // Do not execute this code
    if(slowpath(checkNil && ! cls))return nil;
     // Do not execute this code
    if(fastpath(! cls->ISA()->hasCustomAWZ())) {return _objc_rootAllocWithZone(cls, nil); 
    }
#endif

    // The argument passed in is false
    if (allocWithZone) {
        return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil); 
    }
    // Run objc_msgsend to forward the alloc
    return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc)); 
}
Copy the code

2.0.5 AlloC detailed process supplement

Through 2.0.4, we know that the LLVM system will preferentially execute the alloc method once. Analyze the source code and add a detailed allO execution flow chart.

3.0 New and init execution process

+ (id)new {
    return [callAlloc(self, false/*checkNil*/) init];
}
Copy the code

We see that the implementation of new is just doing callAlloc(), and then doing init. Equivalent to [[XX alloc] init].

4.0 summarize

Alloc, new, both initialize objects and allocate memory. 2, alloc+int is equivalent to new 3, an object occupies at least 16 bytes of memory