Basic memory management rules

  1. Self-generated objects are held by themselves
  2. Objects that are not generated by themselves can be held by themselves
  3. You must release objects you hold when they are no longer needed
  4. Objects that you do not own cannot be released

MRC

1. Keep the generated objects

Hold objects generated by methods starting with alloc, new, copy, mutableCopy, etc. Who are you? I am a user of this method myself.

Here are chestnuts:

{ Person *p1 = [[Person alloc] init]; . [p1 release]; }Copy the code

An object generated by alloc is held by P1 and released when p1 no longer needs to hold the object. If you do not release it, the object can no longer be accessed outside the scope, causing a memory leak.

2. You can hold objects that are not generated by yourself

Except for the four prefixes mentioned above, objects created by other methods are not owned by themselves.

Suppose the Person class has the following methods:

+ (instancetype)object {
  id p = [[Person alloc] init];
  return p;
}Copy the code

According to the naming conventions, the semantics of an object are that the user takes possession of the object, but does not own it. So the consumer calls the method like this:

Person *p1 = [Person object]; // End of sentence, because the user thinks I don't hold the object, why release itCopy the code

But if we look at the code in the object method, we can see that P1 is actually holding the object (as the allocObject method does below), which causes a memory leak.

Ok, so how about [p release] before return p, if that’s the case return P really does have a p.

I thought so myself, then I can release it outside the method. Because I overlooked the fact that this method usually hides the details from the user, only the ghost except me would write something like this.

Person *p = [Person object];
[p release];Copy the code

The correct object method would look like this:

+ (instancetype)object {
  id p = [[Person alloc] init];
  [p autoreleasepool];
  return p;
}Copy the code

Register P with the auto release pool and release p once the scope of the auto release pool ends.

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; Person *p = [Person object]; [pool drain]; // The Person object is freedCopy the code

Recalling the first rule, for example, if you have an allocObject method:

+ (instancetype)allocObject {
  id p = [[Person alloc] init];
  return p;
}Copy the code

[P autoreleasepool] is not used in this method because, according to the naming convention, the allocObject method says, I create the object and hold it. So the user creates the object with Person *p = [Person allocObject], when it is no longer needed [p release].

3. Release the objects you hold when they are no longer needed

The NSObject class has a dealloc method that is automatically called when the object’s reference count is zero to free the object’s memory. If you override the method, you must write [super dealloc] at the end.

In addition to the above mentioned self-generated and held objects need to be released, there is another point:

Person *p = [Person object]; // From the previous code, p does not hold the Person object [p retain]; // p holds the object [p release]; // Release the objectCopy the code

4. Objects that you do not own cannot be released

Person *p = [[Person alloc] init];
[p release];
[p release];Copy the code

The first release doesn’t hold that object anymore, and the second release doesn’t do much good.

I read that this would cause the program to crash, but it didn’t. The console just said: Repeat Release.

Another chestnut:

@autoreleasepool {
  Person *p1 = [Person object];
  [p1 release];
}Copy the code

P1 does not hold objects, so it should not be able to call Release, but the above code runs correctly.

I wonder what the gods think.

About 5.AutoreleasePool

AutoreleasePool acts as a kind of delayed destruction. When AutoreleasePool’s scope ends, objects registered in AutoreleasePool receive a release message and are then destroyed.

ARC

1. __strongThe modifier

The __strong modifier is the default modifier for all ID types and object types. The following two statements are equivalent:

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

When obj goes out of scope, the strong reference to the NSObject object disappears and the object is destroyed automatically.

The first rule for memory management is that objects generated and held by themselves are automatically freed in ARC mode. The next point is about rule number two.

@autoreleasepool {Person *p1 = [Person object]; . } + (instancetype)object { Person *p = [[self alloc] init]; return p; }Copy the code

ARC automatically inserts [p autoRelease] before return p. P1 has a strong reference by default. When autoReleasepool is out of scope, p1’s strong reference becomes invalid and the object is released. The above code should be equivalent to the following code in MRC mode:

@autoreleasepool { Person *p1 = [Person object]; [p1 retain]; . [p1 release]; } + (instancetype)object { Person *p = [[self alloc] init]; [p autorelease]; return p; }Copy the code

2. __weakThe modifier

There is the following code:

Person *__weak p1;
NSLog(@"%@", p1);
@autoreleasepool {
  Person *p2 = [Person object];
  p1 = p2;
  NSLog(@"%@", p1);
}
NSLog(@"%@", p1);Copy the code

Running the code above shows that p1 is automatically set to nil when the object weakly referenced by P1 is destroyed. But look at the __strong modifier:

Person *p1;
@autoreleasepool {
  p1 = [Person object];
  NSLog(@"%@", p1);
}
NSLog(@"%@", p1);Copy the code

Once out of autoreleasepool’s scope, P1 is not set to nil, and the contents of P1 can still be accessed, but once out of scope, the contents should not be accessed.