What is a circular reference
Simply put, a circular reference is: A retains B, B retains a, and neither a nor B can be released.
Why ID is assign and not retain
It can be guessed from the title of the article that the reason ID is assign rather than retain is related to your circular reference. The reason is true.
The ID is assign rather than retain, because retain may lead to circular references, note that the word here is possible, not necessarily.
Here is an example to illustrate the situation.
Note to strictly follow the memory management
First, create a protocol, the Protocol has a method, the function of the method is to change the color
1 #import <Foundation/Foundation.h>23@protocol zychangecolordelegate < Nsobject>45 -(void) changecolor; 6 7 @end
Ii. creating two View controller classes
1. View controllers A and B, two view controllers are added to the navigation, jump to B, click on the button on the B can change the background color of a. Here in order to explain why the ID is assign instead of retain, use proxy to pass the value, other methods do not discuss. The buttons on a and B are all implemented by XIB.
1.1 The first way to use retain does not cause circular references
Part of the code in the entry class
1 Zyaviewcontroller *aviewcontroller =//A +1 =12 Uinavigationcontroller *navigationcontroller = [ [Uinavigationcontroller alloc] initwithrootviewcontroller:aviewcontroller]; //a +1 +1 =23 Self.window.rootViewController =//a +1+1 +1 = 3//A 3-1 = 2// A 2-1 = 1
Start by carefully calculating the reference count for a and B from the Ingress class
1 //A2 #import<UIKit/UIKit.h>3 4 #import "ZYChangeColorDelegate.h"5 6 @interfaceZyaviewcontroller:uiviewcontroller <ZYChangeColorDelegate>7 8 @end9 Ten // ---------------------------------------------------------------------------------- One A #import "ZYAViewController.h" - #import "ZYBViewController.h" - the @implementationZyaviewcontroller - - -- (void) Viewdidload + { - [Super Viewdidload]; + A } at --(Ibaction) GoToNext: (ID) Sender - { -Zybviewcontroller *bviewcontroller =[[Zybviewcontroller alloc] init]; //B +1 -Bviewcontroller.Delegate=Self ; //A 1 +1 = 2 - [Self.navigationcontroller Pushviewcontroller:bviewcontroller Animated:yes]; //B 1 +1 = 2 in [Bviewcontroller release]; //B 2-1 = 1 - } to + #pragmaMark-Protocol method -- (void) ChangeColor the { *Self.view.backgroundColor =[Uicolor Redcolor]; $ }Panax Notoginseng -- (void) Dealloc the { + [Super Dealloc]; A } the + @end
1 //B2 #import<UIKit/UIKit.h>3 4 #import "ZYChangeColorDelegate.h"5 6 @interfaceZybviewcontroller:uiviewcontroller7 8@property (nonatomic, retain)ID<ZYChangeColorDelegate>Delegate;9 Ten @end One A // ------------------------------------------------------------------------------ - #import "ZYBViewController.h" - the @implementationZybviewcontroller - -- (void) Viewdidload - { + [Super Viewdidload]; - + } A at-(Ibaction) Changeabackgroundcolor: (ID) Sender - { - [_delegate ChangeColor]; - } - -- (void) Dealloc in { - [_delegate release]; //A 2-1 = 1 to [Super Dealloc]; +}//When you click the Back button on the navigation bar to get B from the navigation controller pop, the reference count changes to B 1-1 = 0, this time the Dealloc method of B is called, the reference count of a is reduced by 1, and a also pops out of the navigation (where a is the root belongs to the rabbit control When the program ends), the reference count is a 1-1 = 0, and A's Dealloc method is called.
The above scenario does not cause a circular reference because the reference count of a and B is changed to 0 at the appropriate time, and the respective dealloc methods are called.
The following is a case that causes a circular reference
2. Using retain to cause a circular reference, the value needs to be slightly modified: Add a property (or member variable) to a
1 //A2 #import<UIKit/UIKit.h>3 4 #import "ZYChangeColorDelegate.h"5 #import "ZYBViewController.h"6 7 @interfaceZyaviewcontroller:uiviewcontroller <ZYChangeColorDelegate>8 9@property (nonatomic, retain) Zybviewcontroller *Bviewcontroller;Ten One @end A - // ----------------------------------------------------------------------------- - #import "ZYAViewController.h" the - @implementationZyaviewcontroller - - +- (void) Viewdidload - { + [Super Viewdidload]; A at } - --(Ibaction) GoToNext: (ID) Sender - { //note differs from the first notation -_bviewcontroller =[[Zybviewcontroller alloc] init]; //B +1 = 1 -_bviewcontroller.Delegate=Self ; //A 1 +1 = 2 in [Self.navigationcontroller Pushviewcontroller:_bviewcontroller Animated:yes]; //B 1 +1 = 2 - } to + #pragmaMark-Protocol method -- (void) ChangeColor the { *Self.view.backgroundColor =[Uicolor Redcolor]; $ }Panax Notoginseng -- (void) Dealloc the { + [_bviewcontroller release]; A [Super Dealloc]; the } + - @end
The reference count for A and B is now calculated from the Ingress class: At this point, when you leave from the B interface, B pops out of the navigation, the reference count of B is reduced by 1, and the 1,dealloc method is called only when its reference count is 0, so at this point a cannot be released once, and the reference count is 2, when a pop out of the navigation, its reference count is 1, also cannot call the Dealloc method. So neither A nor B can be released, thus forming a form:
B to release himself after the stack found himself a reference count of 1 and then found that as long as a dealloc method executed B can be released to find a go
A want to perform your own Dealloc method to release yourself find if the navigation frees itself, its reference count is still 1 and then finds out that as long as B's Dealloc method executes a, it can be released to find B.
This makes it possible for both parties to release themselves because of the circular reference.
Third, use assign to avoid circular reference
With assign, the reference count is not added to 1 to avoid the case of circular references.
Circular reference--why ID is assign instead of retain