OC object-oriented programming, we often use alloc, init, new to instantiate classes into objects, so how they work, and what is the relationship between them?
One, let’s look at some code
NSObject *objc1 = [NSObject alloc];
NSObject *objc2 = [objc1 init];
NSObject *objc3 = [objc1 init];
NSLog(@"%@ - %p",objc1,&objc1);
NSLog(@"%@ - %p",objc2,&objc2);
NSLog(@"%@ - %p",objc3,&objc3);
Copy the code
Output:
InitViewController.m:(23).NSObject: 0x600000a94be0> - 0x7ffee89358b8
InitViewController.m:(24).NSObject: 0x600000a94be0> - 0x7ffee89358b0
InitViewController.m:(25).NSObject: 0x600000a94be0> - 0x7ffee89358a8
Copy the code
Objc1, objc2, and objC3 are represented by different Pointers to the same memory address.
Why did this happen? The reason for this is in the code:
Click Command + jump to alloc to find nsobjct.h
+ (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
Copy the code
So that’s the end of it, so where do we look at how alloc is implemented
Two, three kinds of breakpoint
There are three ways to see the source code in the library
Method 1:control + step into
objc_alloc: ->
libobjc.A.dylib`objc_alloc: ->
libobjc.A.dylib`_objc_rootAllocWithZone: ->
libsystem_malloc.dylib`calloc: -> ...
Copy the code
Method 2: Symbolic breakpoints
Location: Debug->BreakPoints->Create Symbolic Breakpoint
The symbol alloc appears libobjc.a.dylib +[NSObject alloc]:
Method 3: Look at the assembly
Location: Debug->Debug Workflow->Always show Disassembly
Breakpoint, then go to assembly control + step in will go to libobjc.a.dylib objc_alloc:
All three of the above methods point to the same library libobjc.a.dylib. Let’s examine a library
Third, source code analysis
Objc source code address
How to compile this source code was written in the previous blog objC4-818.2 source code compilation
3.1.0 Alloc implementation principle
MMObject class doesn’t implement anything, right
#import <Foundation/Foundation.h>
#import "MMObject.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
MMObject *objc = [MMObject alloc];
}
return 0;
}
Copy the code
+ (id)alloc {
return _objc_rootAlloc(self);
}
Copy the code
id
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/.true/*allocWithZone*/);
}
Copy the code
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
#if __OBJC2__
if(slowpath(checkNil && ! cls))return nil;
if(fastpath(! cls->ISA()->hasCustomAWZ())) {// +allocWithZone is not implemented
return _objc_rootAllocWithZone(cls, nil);/ / go here
}
#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
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
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);// Calculate the size of memory to be opened
if (outAllocatedSize) *outAllocatedSize = size;
id obj;
if (zone) {
obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
} else{go here obj = (id)calloc(1, size);// Request memory
}
if(slowpath(! obj)) {if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
return _objc_callBadAllocHandler(cls);
}
return nil;
}
if(! zone && fast) {/ / this
obj->initInstanceIsa(cls, hasCxxDtor);// Associate the class with isa
} 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)) {/ / this
return obj;// Return this object
}
construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;
return object_cxxConstructFromClass(obj, cls, construct_flags);
}
Copy the code
Alloc -> _objc_rootAlloc -> callAlloc -> hasCustomAWZ() not implemented +allocWithZone -> _objc_rootAllocWithZone -> _class_createInstanceFromZone allocates memory inside calloc associates ISA with class initInstanceIsa returns objC
3.1.1 MMObject
Class+allocWithZone
#import "MMObject.h"
@implementation MMObject
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static id instance = nil;
@synchronized (self) {
if (instance == nil) {
instance = [superallocWithZone:zone]; }}return instance;
}
@end
Copy the code
The preceding is the same, hasCustomAWZ() will skip it
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
#if __OBJC2__
if(slowpath(checkNil && ! cls))return nil;
if(fastpath(! cls->ISA()->hasCustomAWZ())) {// Does not include custom +allocWithZone
return _objc_rootAllocWithZone(cls, nil);
}
#endif
// No Shortcuts available
if (allocWithZone) {// Go here because allocWithZone is implemented
return ((id(*) (id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);
}
return ((id(*) (id, SEL))objc_msgSend)(cls, @selector(alloc));
}
Copy the code
3.2 init
Implementation principle of
MMObject *objc1 = [objc init];
Copy the code
- (id)init {
return _objc_rootInit(self);
}
Copy the code
id
_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;
}
Copy the code
Init we can see it doesn’t do anything, it just returns an obj, so what’s the use of this? It’s a factory design pattern, so we can do some other things when we initialize it.
3.2 new
Implementation principle of
MMObject *objc2 = [MMObject new];
Copy the code
+ (id)new {
return [callAlloc(self.false/*checkNil*/) init];
}
Copy the code
New calls callAlloc with default false allocWithZone=false and calls init by default.
conclusion
Alloc opens up memory and associates the class with isa Pointers
Init does nothing, returns the principle class, right
[Class new] is equivalent to [[Class alloc]init.