Reference count in Objective-c

Source: Internet
Author: User


Introduction


The Objective-c language uses reference counts to manage memory, that is, each object has a counter that can be incremented or decremented. If you want to keep an object alive, increment its reference count, and after it is exhausted, it decrements its count. A count of 0 means no one is paying attention to the object, so it can be destroyed.



Starting with Mac OS X 10.8, the "Garbage collector" (garbage collector) has officially been deprecated, and it should not be used when writing a Mac OS X program objective-c code, while iOS has never supported garbage collection. Therefore, mastering the reference counting mechanism is very important for learning objective-c. MAC OS x programs are no longer dependent on the garbage collector, and the iOS system does not support this feature and will not be supported in the future.



People who have already used arc may know that all methods related to reference counting cannot be compiled, but let's forget about it for the time being. Those methods do not work in arc, but this article is about referencing counting from a objective-c perspective, and arc is actually a reference counting mechanism, so let's talk about these methods that cannot be called directly when the ARC function is turned on.


Working principle


Under the reference count schema, the object has a counter that indicates how many things are currently trying to keep the object alive. This is called the "Keep Count" (retain count) in objective-c, but it can also be called a reference count (reference count). The NSObject protocol declares the following three methods for manipulating counters to increment or decrement their values:



1) Retain increment hold count.



2) Release decrements the hold count.



3) autorelease decrements the retention count when the autorelease pool is cleaned up later.






is the object creation and retention count operation.






In the object graph, both OBJECTB and OBJECTC refer to Objecta. If both OBJECTB and OBJECTC are no longer using objecta, their retention count is reduced to 0, so they can be destroyed. There are other objects that want to keep OBJECTB and OBJECTC alive, and there are other objects in the application that want to keep those objects alive. If you follow the reference tree, you will eventually find a root object. In a Mac OS x application, this object is a NSApplication object, whereas in an iOS application, it is a UIApplication object. Both are the singleton that is created when the application starts.



The following code helps to understand the use of these methods:


NSMutableArray *array = [[NSMutableArray alloc] init];
NSNumber *number = [[NSNumber alloc] initWithInt:1337];
[array addObject:number];
[number release]; //do something with ‘array‘  [array release];


Because the release method is called directly in the code, it cannot be compiled under arc. In Objective-c, the object returned by the call to the Alloc method is owned by the caller. In other words, the caller has expressed the intention to keep the object alive by Alloc method. However, this is not to say that the object's retention count at this point is 1. In the code implementation of the Alloc or "Initwithint:" method, there may be other objects that also retain this object. Never say that the hold count must be a value, only that the count is incremented for the operation you are performing or decrements.



When you have finished creating the array, add the number object to it. When you call the array's "AddObject:" method, the array is also raised on number by using the Retain method, in order to continue preserving this object. At this point, the retention count is at least 2. Next, the code no longer needs the number object, so it is freed. The retention count is now at least 1. This makes it impossible to use the number variable as usual. After you call release, there is no guarantee that the object you are referring to remains alive. Of course, according to the code in this example, we obviously know that the number object still survives after the release is called, because the array is still referencing it. However, you should never assume that this object must survive, that is, don't write code like this:


NSNumber *number = [[NSNumber alloc] initWithInt:1337];
[array addObject:number];
[number release];
NSLog(@"number = %@", number);


Even if the code above works well in this case, it is still not a good idea. If you call release and the retention count drops to 0 for some reason, the memory of the number object may be recycled, so calling NSLog may cause the program to crash. Why is "possible" because the object occupies memory after "deallocated" (deallocated), just put back to the "Free Memory Pool" (avaiable pool). If the object memory is not yet overwrite when executing NSLog, the object is still valid, and the program does not crash. Therefore, the bug caused by premature release of the object is difficult to debug .



To avoid inadvertently using invalid objects, the pointer will be emptied after the release is generally called. This guarantees that there will be no pointers to invalid objects, often referred to as "hanging pointers" (dangling pointer). For example, you can write code to prevent this from happening:


NSNumber *number = [[NSNumber alloc] initWithInt:1337];
[array addObject:number];
[number release];
number = nil;
Memory management in the property access method


As mentioned earlier, object graphs are composed of interrelated objects. The array in the example just now preserves those objects by calling the Retain method on its elements. Not only the array, but also other objects can retain other objects, which is generally achieved by accessing the "properties", while accessing the property, the relevant instance variable is used to get the method and set method. If the property is "strong relationship" (strong relationship), the Set property value is preserved. For example, a property named Foo is implemented by an instance variable named _foo, so the property is set up as follows:


-(void)setFoo:(id)foo {
         [foo retain];
         [_foo release];
         _foo = foo;
}


This method preserves the new value and frees the old value, and then updates the instance variable to point to the new value. Order is important. If a new value is not retained and the old value is released, and two values point to the same object, then the release operation may cause the system to recycle the object permanently. And the subsequent retain operation is not a decree that has been completely recovered the object of resurrection, so the instance variable is a hanging pointer.


Auto Free Pool


In the reference count schema of Objective-c, the automatic release of a pool is an important feature. Calling release decrements the object's retention count immediately (and may also cause the system to reclaim the object), but sometimes you can call autorelease instead of calling it, which decrements the count at a later time, usually in the next event loop. But it could be done even earlier.



This feature is useful, especially if you want to use it when returning an object in a method. In this case, we are always trying to make the method caller retain its value by hand. For example, there is the following method:


-(NSString *)stringValue {
         NSString *str = [[NSString alloc] initWithFormat:@"I am this: %@", self]; return str;
}


The Str object returned at this time has a 1 more reserved count than expected because the caller alloc the retention count by 1 and no release action corresponds to it. A 1 retention count means that the caller is responsible for handling the extra retention operation. It must be tried to counteract it. This is not to say that the retention count itself must be 1, it may be greater than 1, but that depends on the implementation details within the "Initwithformat:" method. What you need to consider is how to cancel out the extra retention operation. However, you cannot release Str in the method, otherwise the system will recycle the object if it has not yet been returned. This should be done with autorelease, which releases the object at a later time, leaving the caller long enough to retain the return value when needed. In other words, this method guarantees that an object must survive a "method call boundary" boundary. In fact, the release operation executes when the outermost auto-release pool is emptied, unless you have your own auto-release pool, which is the next event loop for the current thread. Overwrite the StringValue method and use Autorelease to release the object:


-(NSString *)stringValue {
         NSString *str = [[NSString alloc] initWithFormat:@"I am this: %@", self]; return [str autorelease];
}


After the modification, the StringValue method returns the NSString object to the caller, and the object must survive. So we can use it this way:


NSString *str = [self stringValue];
NSLog(@"The string is: %@", str);


Since the returned STR object will be automatically released later, the extra retention operation will naturally be offset, eliminating the need to perform memory management operations. Because the release operation in the auto-free pool is not executed until the next event loop, the NSLog statement does not need to perform a manual hold operation until the STR object is used. However, if you want to hold this object (such as setting it to an instance variable), you need to keep it and release it later:


_instanceVariable = [[self stringValue] retain]; //...  [_instaceVariable release];


Thus, autorelease can prolong the life of the object so that it can survive for some time after crossing the method call boundary.


Retaining ring


One of the frequently asked questions when using the reference counting mechanism is the "reserved Ring" (retain cycle), which is a loop of multiple objects that are referenced by each other. This causes a memory leak because objects in the loop will not have their retention count reduced to 0. For each object in the loop, there is at least one other object that references it.






For example, in this loop, the object's retention count is 1. In a garbage collection environment, this is often identified as an island of isolation. At this point, the garbage collector reclaims all three objects. In the reference counting architecture of objective-c, this convenience is not enjoyed. A "weak reference" (weak reference) is typically used to resolve this problem, or another object is no longer persisted from an object in the external command loop. Both of these methods can break the retention ring, thus avoiding memory leaks.


Summary


The reference counting mechanism manages memory through counters that can increment by decreasing. After the object is created, its retention count is at least 1. If the hold count is positive, the object continues to survive. When the hold count is reduced to 0 o'clock, the object is destroyed.



In the object life cycle, the rest of the objects are referenced to preserve or dispose of this object. The hold and release operations increment and decrement the hold count, respectively.






Reference count in Objective-c


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.