After summarizing Effective Objective-C, I wanted to read an advanced iOS book, so I picked Up Advanced Programming in Objective-C.

There are three chapters in this book. I summarize each chapter and share it with you with appropriate extensions. You can see the overall structure of these three chapters from the following picture:

Note that this structure is not the same as the structure in the book, but is slightly adjusted based on the structure in the book.

Objective-c uses the retainCount mechanism to determine if an object needs to be freed. At the end of each runloop iteration, the object’s retainCount is checked, and if retainCount is zero, the object has no further use and can be released. Memory management is done through retainCount, either manually or through the ARC mechanism.

Let’s start with manual memory management:

Manual memory management

I personally feel that before learning a new technology, you need to understand its core idea. Once you understand the core ideas, you will be able to grasp the technical points more quickly:

Memory management ideas

  • Idea 1: You own the objects you generate.
  • Idea 2: We can hold objects that we do not generate.
  • Idea 3: Release objects you hold when you no longer need them.
  • Thought 4: You can’t release objects you don’t own.

From the above perspective, there are three types of manipulation we can do on objects: create, hold, release, and discard. There are four. Their corresponding objective-C method and reference count changes are:

The object operation Objecctive – C method Reference count changes
Generate and hold objects Alloc/new/copy/mutableCopy method + 1
Hold the object Retain method + 1
Release object Release method – 1
Discarded objects Dealloc method There is no

Use the illustrations in the book to visualize these four operations:

Let’s start by explaining each of the four ideas above:

Idea 1: You own the objects you generate

When an object is generated, it is held after the object is generated using a method starting with the following name:

  • alloc
  • new
  • copy
  • mutableCopy

An 🌰 :

id obj = [[NSObject alloc] init];// Hold the newly generated object
Copy the code

After this line of code, the pointer to generating and holding [[NSObject alloc] init] is assigned to obj, which means that the pointer to obj strongly references the object [[NSObject alloc] init].

The same applies to new methods:

id obj = [NSObject new];// Hold the newly generated object
Copy the code

Note that assigning a pointer that holds an object to a pointer variable is not limited to these four method names, but also to all method names that begin with them:

  • allocThisObject
  • newThatObject
  • copyThisObject
  • mutableCopyThatObject

An 🌰 :

id obj1 = [obj0 allocObject];// Generate and hold objects according to the above naming rules
Copy the code

Its internal implementation:

- (id)allocObject
{
    id obj = [[NSObject alloc] init];// Hold the newly generated object
    return obj;
}
Copy the code

On the other hand, if it does not comply with the above naming rules, then the generated object will not be held. See the internal implementation of a createObject method that returns an object that does not comply with the above naming rules 🌰 :

- (id)createObject
{
    id obj = [[NSObject alloc] init];// Hold the newly generated object
    [obj autorelease];// Get the object, but do not own it
    return obj;
}
Copy the code

After returning from this method, the returned object cannot be held. Because we’re using autorelease here. Autorelease provides the ability to automatically and correctly release objects when they are outside their specified lifetime range (more on that later).

That is, generating an object that is not held by the caller can be done with an AutoRelease (such as the Array class method of NSMutableArray).

My personal understanding is that with the autoRelease method, ownership of objects is transferred to the automatic release pool. So it is: the caller gets the object, but the object is not yet held by the caller.

From this example that does not comply with the naming rules to lead to idea 2:

Idea 2: We can hold objects that we do not generate

We now know that an object cannot be held simply by returning an instance of the object through the above method, which does not comply with the naming convention. But there is an operation that holds the returned object: the retain method holds the pointer variable to hold the newly generated object:

id obj = [NSMutableArray array];// Objects that are not generated and held by themselves
[obj retain];// Hold the newly generated object
Copy the code

Note that the non-owned objects returned by [NSMutableArray Array] are implemented using the autoRelease method described above. So if you want to hold this object, you need to call the retain method.

Idea 3: Release objects you hold when you no longer need them

The owner of an object is obligated to release the object when it is no longer needed. Notice, an obligation, not a right, notice the difference between the two words.

Let’s look at an example of releasing an object:

id obj = [[NSObject alloc] init];// Hold the newly generated object
[obj doSomething];// Do something with this object
[obj release];// When you're done, release the object
Copy the code

The same applies to objects that are not generated and held by themselves (thought 2) :

id obj = [NSMutableArray array];// Objects that are not generated and held by themselves
[obj retain];// Hold the newly generated object
[obj soSomething];// Do something with this object
[obj release];// When you're done, release the object
Copy the code

Possible interview questions: Does calling the release method of an object destroy the object? The answer is no: calling the release method of the object only calls the reference counter of the object -1, and when the reference counter of the object is 0, the dealloc method is called to free the object’s memory.

Idea 4: You can’t release objects you don’t own

In the release of objects, we can only release the already held objects, non-own objects can not be released by their own. It’s common sense: Just as you can withdraw money from your own bank account, it’s not right to take money from someone else’s (unless it’s yours… Just a random example).

Two disallowed situations:

1. Release an obsolete object

id obj = [[NSObject alloc] init];// Hold the newly generated object
[obj doSomething];// Use this object
[obj release];// Release the object, it is no longer held
[obj release];// Release obsolete objects, crash
Copy the code

2. Release objects you don’t own

id obj = [NSMutableArray array];// Objects that are not generated and held by themselves
[obj release];// Free objects that are not owned by you
Copy the code

Consider: What circumstances could cause an object to lose its owner?

  1. To point a pointer variable to one object to another.
  2. Sets a pointer variable to an object to nil.
  3. When a program releases an owner of an object.
  4. When an object is deleted from a Collection class.

Now that we know the four ideas of reference counting memory management, let’s look at the four methods of manipulating reference counting:

The realization of the alloc/retain/release/dealloc

In a sense, the implementation of GNUstep and the Foundation framework is similar. So the authors of this book use GNUstep’s source code to speculate on the implementation of Apple’s Cocoa framework.

Let’s start with each method and compare the respective implementations with GNUstep and Apple implementations (tracking application execution and author guesses).

GNUstep implementation:

Alloc method

//GNUstep/modules/core/base/Source/NSObject.m alloc:

+ (id) alloc
{
    return [self allocWithZone: NSDefaultMallocZone()];
}
 
+ (id) allocWithZone: (NSZone*)z
{
    return NSAllocateObject(self.0, z);
}
Copy the code

Here the NSAllocateObject method allocates the object. Take a look at its internal implementation:

//GNUstep/modules/core/base/Source/NSObject.m NSAllocateObject:

struct obj_layout {
    NSUInteger retained;
};
 
NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone)
{
    intSize = Calculate the size of memory needed to hold the object;id new = NSZoneMalloc(zone, 1, size);// Return a new instance
    memset (new, 0, size);
    new = (id)&((obj)new)[1];
}
Copy the code
  1. The NSAllocateObject function uses the NSZoneMalloc function to allocate the memory needed to store the object.
  2. Obj_layout is used to hold the reference count and write it to the head of the object’s memory.

The reference count of the object can be obtained using the retainCount method:

GNUstep/modules/core/base/Source/NSObject.m retainCount:

- (NSUInteger) retainCount
{
    return NSExtraRefCount(self) + 1;
}
 
inline NSUInteger
NSExtraRefCount(id anObject)
{
    return ((obj_layout)anObject)[- 1].retained;
}
Copy the code

As you can see, passing anObject to NSExtraRefCount, we retrieved the reference count by accessing the. Retained variable of the object’s memory header.

Retain method

//GNUstep/modules/core/base/Source/NSObject.m retain: - (id)retain { NSIncrementExtraRefCount(self); return self; } retained void NSIncrementExtraRefCount(id anObject) {// Retained variables exceed the maximum value. If (((obj)anObject)[-1]. Retained == UINT_MAX - 1){ [NSException raise: NSInternalInconsistencyException format: NSIncrementExtraRefCount() asked to increment too far]; } ((obj_layout)anObject)[-1].retained++; // repeat +1}Copy the code

Release method

//GNUstep/modules/core/base/Source/NSObject.m release

- (void)release
{
    // If the current reference count = 0, call the dealloc function
    if (NSDecrementExtraRefCountWasZero(self)) {[selfdealloc]; }}BOOL NSDecrementExtraRefCountWasZero(id anObject)
{
    // Return yes if the current retained value = 0
    if (((obj)anObject)[- 1].retained == 0) {return YES;
    }
    
    // If greater than 0, -1 and return NO
    ((obj)anObject)[- 1].retained--;
    return NO;
}
Copy the code

Dealloc method

//GNUstep/modules/core/base/Source/NSObject.m dealloc

- (void) dealloc
{
    NSDeallocateObject (self);
}
 
inline void NSDeallocateObject(id anObject)
{
    obj_layout o = &((obj_layout)anObject)[- 1];
    free(o);/ / release
}
Copy the code

To summarize the above methods:

  • The objective-C object holds the reference count as a whole number.
  • After the alloc or retain methods are called, the reference count +1.
  • When release is called, the reference count is -1.
  • When the reference count is 0, the dealloc method is called to discard the object.

Here’s a look at apple’s implementation:

Realization of Apple

Alloc method

By setting a breakpoint on the alloc class method of the NSObject class, we can see that the called function is executed:

  • +alloc
  • +allocWithZone:
  • Class_createInstance // Generates an instance
  • Calloc // Allocates memory blocks

retainCount:

  • __CFdoExternRefOperation
  • CFBasicHashGetCountOfKey

Retain method

  • __CFdoExternRefOperation
  • CFBasicHashAddValue

Release method

  • __CFdoExternRefOperation
  • CFBasicHashRemoveValue

We can see that they all call a common __CFdoExternRefOperation method.

Take a look at its implementation:

int __CFDoExternRefOperation(uintptr_t op, id obj) {

    CFBasicHashRefTable = hash table of the object (obj);int count;
 
    switch (op) {
    case OPERATION_retainCount:
        count = CFBasicHashGetCountOfKey(table, obj);
        return count;
        break;

    case OPERATION_retain:
        count = CFBasicHashAddValue(table, obj);
        return obj;
    
    case OPERATION_release:
        count = CFBasicHashRemoveValue(table, obj);
        return 0== count; }}Copy the code

As you can see, __CFDoExternRefOperation uses the switch statement to make specific method calls for different operations. If op is OPERATION_retain, the retain method is removed, and so on.

Can guess the upper retainCount, retain, release method of implementation:

- (NSUInteger)retainCount
{
    return (NSUInteger)____CFDoExternRefOperation(OPERATION_retainCount,self);
}

- (id)retain
{
    return (id)____CFDoExternRefOperation(OPERATION_retain,self);
}

// The return value should be id, the original book should be wrong
- (id)release
{
    return (id)____CFDoExternRefOperation(OPERATION_release,self);
}
Copy the code

If we look at the name of the execution function in each statement in the Switch, it seems to have something to do with hashes, suggesting that Apple’s management of reference counts should be done through Hash tables.

In this table, key is the address of the memory block, and the corresponding value is the reference count. That is, it holds information about the reference count of each referenced chunk of memory.

So what are the benefits of using hash tables to manage memory?

Since the counter table holds memory block addresses, we can use this table to:

  • Identify the location of the corrupted memory block.
  • When detecting memory leaks, you can check to see if the owner of each object exists.

autorelease

Autorelease introduction

When an object goes out of scope, the object instance’s release method is called. Autorelease is used as follows:

  1. Generates and holds an NSAutoreleasePool object.
  2. Calls the autoRelease method of the allocated object.
  3. Discard the NSAutoreleasePool object.

All objects that have called the autoRelease method will call the Release method (reference count-1) when the NSAutoreleasePool object is discarded:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease];
[pool drain];// obj calls release
Copy the code

NSRunLoop During each loop, the NSAutoreleasePool object is generated or discarded. That is, if there are a large number of Autorelease variables, they will not be destroyed until the NSAutoreleasePool object is discarded (NSAutoreleasePool is released as soon as the RunLoop is heard to be about to go to sleep), causing problems with memory explosion:

for (int i = 0; i < imageArray.count; i++)
{
    UIImage *image = imageArray[i];
    [image doSomething];
}
Copy the code

Therefore, it is necessary to nest another autorelease pool to manage temporary autorelease variables when appropriate:

for (int i = 0; i < imageArray.count; i++)
{
    / / temporary pool
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    UIImage *image = imageArray[i];
    [image doSomething];
    [pool drain];
}
Copy the code

Possible interview questions: When will automatic release pools be created? A: the auto-release pool is created after the runloop detects the event and starts, and the runloop for the child thread is not working by default and cannot be created actively, so it must be created manually. For example 🌰 : the main method of the custom NSOperation class must be added to the automatic release pool. Otherwise, after going out of scope, the auto-free object will leak memory because there is no auto-free pool to process itself.

Autorelease implementation

As before, we’ll look at GNUstep and Apple’s implementation separately.

GNUstep implementation

//GNUstep/modules/core/base/Source/NSObject.m autorelease

- (id)autorelease
{
    [NSAutoreleasePool addObject:self];
}
Copy the code

If the NSObject class’s autorelease method is called, the object is appended to the array in the NSAutoreleasePool object in use (the authors assume a simplified source code) :

//GNUstep/modules/core/base/Source/NSAutoreleasePool.m addObject

+ (void)addObject:(id)anObj
{
    NSAutoreleasePool*pool = get the pool that is being usedNSAutoreleasePoolobjectif(pool ! =nil){
        [pool addObject:anObj];
    }else{
        NSLog(@"NSAutoreleasePool object does not exist"); }} - (void)addObject:(id)anObj
{
    [pool.array addObject:anObj];
}
Copy the code

That is, the essence of the AutoRelease instance method is to call the addObject class method of the NSAutoreleasePool object, which is then appended to the array of the NSAutoreleasePool object in use.

Look again at the NSAutoreleasePool drain method:

- (void)drain
{
    [self dealloc];
}

- (void)dealloc
{
    [self emptyPool];
    [array release];
}

- (void)emptyPool
{
    for(id obj inarray){ [obj release]; }}Copy the code

We can see that in the emptyPool method, we actually release every object in the array.

Realization of Apple

We can confirm the implementation of AutoRelease in Apple by objC4 / nsobjject. Mm:

objc4/NSObject.mm AutoreleasePoolPage
 
class AutoreleasePoolPage
{
    static inline void *push()
    {
        // Generates or holds an NSAutoreleasePool class object
    }

    static inline void pop(void *token)
    {
        // Discard the NSAutoreleasePool class object
        releaseAll();
    }
    
    static inline id autorelease(id obj)
    {
        // equivalent to the addObject method of the NSAutoreleasePool classAutoreleasePoolPage * Page = Get the instance of AutoreleasePoolPage in use; autoreleaesPoolPage->add(obj) }id *add(id obj)
    {   
        // Appends the object to the internal array
    }
    
    void releaseAll()
    {
        // Call the release method of the object in the inner array}};/ / pressure stack
void *objc_autoreleasePoolPush(void)
{
    if (UseGC) return nil;
    return AutoreleasePoolPage::push();
}
 
/ / out of the stack
void objc_autoreleasePoolPop(void *ctxt)
{
    if (UseGC) return;
    AutoreleasePoolPage::pop(ctxt);
}
Copy the code

Take a look at the external calls:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Equivalent to objc_autoreleasePoolPush
 
id obj = [[NSObject alloc] init];
[obj autorelease];
// equivalent to objc_autoRelease (obj)
 
[NSAutoreleasePool showPools];
// Check the NSAutoreleasePool status
 
[pool drain];
// Equivalent to objc_autoreleasePoolPop(pool)
Copy the code

As you can see from the function name, push and POP are performed on autoRelease. The release operation is performed when the object is destroyed.

Possible interview questions: how did apple implement autoreleasepool? Autoreleasepool is implemented as an array of queues and is implemented through the following three functions: • objc_autoreleasepoolPush • objc_autoreleasepoolPop • Objc_autorelease (free internal)

ARC Memory Management

Memory management ideas

You learned about manual memory management for non-ARC mechanisms, reference counting operations, and auto-free pools. Now let’s learn about working with ARC.

The idea of memory management under ARC and non-ARC mechanisms is the same:

  • Self generated objects, own.
  • Objects that are not generated by themselves can be held by themselves.
  • Release objects when they are no longer needed.
  • Objects that are not owned by you cannot be released.

With ARC, the compiler can automatically manage memory, reducing the development effort. But we still sometimes need four ownership modifiers to work with ARC for memory management

Four ownership modifiers

However, with ARC we sometimes need to append the ownership declaration (the following is from the official documentation) :

  • __strong: is the default. An object remains “alive” as long as there is a strong pointer to it.
  • __weak: specifies a reference that does not keep the referenced object alive. A weak reference is set to nil when there are no strong references to the object.
  • __unsafe_unretained: specifies a reference that does not keep the referenced object alive and is not set to nil when there are no strong references to the object. If the object it references is deallocated, the pointer is left dangling.
  • __autoreleasing: is used to denote arguments that are passed by reference (ID *) and are autoreleased on return.

Here’s a look at each of these modifiers:

__strong modifier

The __strong modifier is the default ownership modifier for ID types and object types:

__strong

id obj = [NSObject alloc] init];
Copy the code

Is equal to:

id __strong obj = [NSObject alloc] init];
Copy the code

Take a look at the memory management process:

{
    id __strong obj = [NSObject alloc] init];//obj holds the object
}
//obj is out of scope, strong reference invalid
Copy the code

The __strong modifier represents a strong reference to an object. Variables with strong references are discarded when they are out of scope.

Assigning values to each other between variables modified by the __strong modifier:

id __strong obj0 = [[NSObject alloc] init];//obj0 holds object A
id __strong obj1 = [[NSObject alloc] init];//obj1 holds object B
id __strong obj2 = nil;//ojb2 does not hold any objects
obj0 = obj1;//obj0 strongly references object B; Object A is no longer referenced by OjB0 and is discarded
obj2 = obj0;Obj0, ojb1, and obj2 all strongly reference B
obj1 = nil;//obj1 no longer strongly references object B
obj0 = nil;//obj0 no longer strongly references object B
obj2 = nil;//obj2 no longer strongly references object B. There are no more strong references to object B. Object B is deprecated
Copy the code

Furthermore, __strong can initialize a variable to nil: id __strong obj0; This also applies to: id __weak obj1; id __autoreleasing obj2;

To summarize: being modified by __strong is equivalent to a strong reference to an object. Once an object has a strong reference to itself, the reference count is +1 and it is not discarded by the system. If this object is no longer strongly referenced, it will be discarded by the system.

__strong internal implementation:

Generate and hold objects:

{
    id __strong obj = [NSObject alloc] init];//obj holds the object
}
Copy the code

Compiler simulation code:

id obj = objc_mesgSend(NSObject.@selector(alloc));
objc_msgSend(obj,@selector(init));
objc_release(obj);// Go out of scope, release the object
Copy the code

Let’s take a look at constructors that don’t use naming conventions:

{
    id __strong obj = [NSMutableArray array];
}
Copy the code

Compiler simulation code:

id obj = objc_msgSend(NSMutableArray.@selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);
Copy the code

Objc_retainAutoreleasedReturnValue role: hold the object, the object to register autoreleasepool and return.

There is also objc_autoreleaseReturnValue, so let’s look at its use:

+ (id)array
{
   return [[NSMutableArray alloc] init];
}
Copy the code

Compiler simulation code:

+ (id)array
{
   id obj = objc_msgSend(NSMutableArray.@selector(alloc));
   objc_msgSend(obj,, @selector(init));
   return objc_autoreleaseReturnValue(obj);
}
Copy the code

Objc_autoreleaseReturnValue: Returns the object registered with AutoReleasepool.

__weak modifier

__weak usage:

__weak modifiers mostly solve the problem of circular references: if two objects strongly refer to each other and both lose external references to themselves, then an “island” can never be released, such as 🌰 :

@interface Test:NSObject
{
    id __strong obj_;
}

- (void)setObject:(id __strong)obj;
@end

@implementation Test
- (id)init
{
    self = [super init];
    return self;
}

- (void)setObject:(id __strong)obj
{
    obj_ = obj;
}
@end
Copy the code
{
    id test0 = [[Test alloc] init];//test0 strongly references object A
    id test1 = [[Test alloc] init];Test1 strongly references object B
    [test0 setObject:test1];Test0 strongly references object B
    [test1 setObject:test0];Test1 strongly references object A
}
Copy the code

Because both generated objects (lines 1, 2) and set methods (lines 3, 4) are strong references, we create situations where two objects strongly reference each other:

So, we need to break one of these strong citations:

@interface Test:NSObject
{
    id __weak obj_;// Change from __strong to __weak
}

- (void)setObject:(id __strong)obj;
@end
Copy the code

In this way, the two are only weak references to each other:

Internal implementation of __weak

{
    id __weak obj1 = obj;
}
Copy the code

Compiler simulation code:

id obj1;
objc_initWeak(&obj1,obj);// Initialize a variable with an __weak attached
id tmp = objc_loadWeakRetained(&obj1);// Retrieve the object referenced by the __weak modifier variable and retain it
objc_autorelease(tmp);// Register the object in autoreleasepool
objc_destroyWeak(&obj1);// Release the variable with an __weak attached
Copy the code

This confirms one feature of __weak: using variables with __weak modifiers is using objects registered in Autoreleasepool.

The objc_initWeak method and objc_destroyWeak method are highlighted here:

  • Objc_initWeak: Initializes a variable with an __weak attached, using objc_strongWeak(&obj1, obj) to Hash the obj object with &obj1 as the key.
  • Objc_destroyWeak: Releases a variable with an __weak attached. Run objc_storeWeak(&obj1,0) to query &obj1 in the weak table and delete the key from the weak table.

Note: Since the same object can be assigned to multiple variables with an __weak attached, it is possible to register the addresses of multiple variables for the same key value.

When an object is no longer held by anyone, it needs to be released as follows:

  • objc_dealloc
  • dealloc
  • _objc_rootDealloc
  • objc_dispose
  • objc_destructInstance
  • objc_clear_deallocating
    • Gets the address of the deprecated object from the weak table
    • Assign nil to all addresses with an __weak modifier variable included in the record
    • Delete the record from the weak table
    • Removes the addresses of obsolete objects from the reference count table

__autoreleasing modifier

Use of __autoreleasing

In ARC, you can use @AutoReleasepool instead of NSAutoreleasePool. The __autoreleasing modifier modifies variables instead of calling the autorelease method of an object (the object is registered with autoreleasepool) when ARC is invalid.

When talking about the __autoreleasing modifier, we have to mention __weak:

id  __weak obj1 = obj0;
NSLog(@"class = %@",[obj1 class]);
Copy the code

Is equal to:

id __weak obj1 = obj0;
id __autoreleasing tmp = obj1;
NSLog(@"class = %@",[tmp class]);// The object registered in the automatic release pool is actually accessed
Copy the code

To access the __weak modifier variable (obj1), you must access the object registered with autoreleasepool (TMP). Why is that?

Because the __weak modifier only holds a weak reference to an object, there is no guarantee that the object has not been deprecated when it is accessed in the future. Therefore, if this object is registered with Autoreleasepool, it is guaranteed to exist until the end of the @Autoreleasepool block.

Internal implementation of __autoreleasing

Assigning an object to a variable with the __autoreleasing modifier is equivalent to calling the object’s autorelease method when ARC is invalid.

@autoreleasepool{
    id __autoreleasing obj = [[NSObject alloc] init];
}
Copy the code

Compiler simulation code:

id pool = objc_autoreleasePoolPush();/ / the pool into the stack
id obj = objc_msgSend(NSObject.@selector(alloc));
objc_msgSend(obj, @selector(init));
objc_autorelease(obj);
objc_autoreleasePoolPop(pool);/ / the pool a stack
Copy the code

Here we can see three methods: pool push, autorelease, and dump.

Rules under ARC

We know that the compiler will help us manage memory under ARC, but there are some rules to follow at compile time, and the authors list the following for us:

  1. Cannot use retain/release/retainCount/autorelease
  2. Cannot use the NSAllocateObject/NSDeallocateObject
  3. The method name rules for memory management must be followed
  4. Do not call dealloc explicitly
  5. Use the @AutoRelease block instead of NSAutoreleasePool
  6. Unusable areas (NSZone)
  7. Object variables cannot be members of C language constructs
  8. Explicitly convert id and void*

1. You can’t use retain/release/retainCount/autorelease

Under the ARC mechanism using retain/release/retainCount/autorelease method, will cause a compiler error.

2. Cannot use NSAllocateObject/NSDeallocateObject

Under the ARC mechanism using NSAllocateObject/NSDeallocateObject method, will cause a compiler error.

3. The method name rules for memory management must be followed

Methods that generate/hold objects must follow the following naming rules:

  • alloc
  • new
  • copy
  • mutableCopy
  • init

The first four methods have been described. The requirements for the init method are more stringent:

  • Must be an instance method
  • Must return object
  • The type of the returned object must be an ID type or an object type of the method declaration class

4. Do not explicitly call dealloc

When an object is deprecated, the system calls the object’s dealloc method regardless of whether ARC is valid or not.

We can only write in the dealloc method what we need to do when an object is deprecated (such as removing a registered observer object), but we cannot call the dealloc method manually.

Note that [super dealloc] is also called when ARC is invalid:

- (void)dealloc
{
    // The processing of this object
    [super dealloc];
}
Copy the code

5. Use the @AutoRelease block instead of NSAutoreleasePool

ARC must use the @autoRelease block instead of NSAutoreleasePool.

6. Cannot use NSZone

NSZone has been ignored in the current runtime system (where __OBC2__ is set).

7. Object variables cannot be used as members of C language structures

C constructs with Objective-C object type variables can cause errors because C has no way of managing the lifetime of the structure’s members in the protocol.

8. Explicitly convert id and void*

Non-arc, these two types can be assigned directly

id obj = [NSObject alloc] init];
void *p = obj;
id o = p;
Copy the code

This will cause a compilation error under ARC. To avoid errors, we need to convert through __bridege.

id obj = [[NSObject alloc] init];
void *p = (__bridge void*)obj;// Explicit conversion
id o = (__bridge id)p;// Explicit conversion
Copy the code

attribute

Take a look at the relationship between property declarations and ownership modifiers

Attribute keyword Ownership modifier
assign __unsafe_unretained
copy __strong
retain __strong
strong __strong
__unsafe_unretained __unsafe_unretained
weak __weak

__unsafe_unretained: __unsafe_unretained means that the access method assigns values directly to the instance variable.

Unsafe, as opposed to weak. We know that when the weak object is destroyed, the pointer is automatically set to nil. __unsafe_unretained doesn’t, but instead becomes a null pointer. Note that null Pointers do not occur when dealing with non-object properties.

That concludes the first chapter, and the second will be published next Monday

Extended literature:

  1. Apple:Transitioning to ARC Release Notes
  2. Mosquito coil: Probably the most comprehensive memory management article ever
  3. Smile and Feifei: iOS written interview question (6) — Memory management
  4. IOS Programming (Version 4)

This post has been synced to my blog: Portal

— — — — — — — — — — — — — — — — — — — — — — — — — — — — on July 17, 2018 update — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Pay attention!!

The author recently opened a personal public account, mainly to share programming, reading notes, thinking articles.

  • Programming articles: including selected technical articles published by the author before, and subsequent technical articles (mainly original), and gradually away from iOS content, will shift the focus to improve the direction of programming ability.
  • Reading notes: Share reading notes on programming, thinking, psychology, and career books.
  • Thinking article: to share the author’s thinking on technology and life.

Because the number of messages released by the official account has a limit, so far not all the selected articles in the past have been published on the official account, and will be released gradually.

And because of the various restrictions of the major blog platform, the back will also be released on the public number of some short and concise, to see the big dry goods article oh ~

Scan the qr code of the official account below and click follow, looking forward to growing with you