Using Weak–strong Dance Technology
Block can refer to self directly, but be very careful to refer to self in the block. Because self is referenced at block, it can cause circular references. As shown in the following example:
[OBJC]View Plaincopy
- @interface Ksviewcontroller ()
- {
- ID _observer;
- }
- @end
- @implementation Ksviewcontroller
- -(void) Viewdidload
- {
- [Super Viewdidload];
- additional setup after loading the view, typically from a nib.
- Kstester * tester = [[Kstester alloc] init];
- [Tester Run];
- _observer = [[Nsnotificationcenter Defaultcenter]
- addobserverforname:@ "Testnotificationkey"
- Object: Nil queue: nil usingblock:^ (nsnotification *n) {
- NSLog (@ "%@", self );
- }];
- }
- -(void) Dealloc
- {
- if (_observer) {
- [[Nsnotificationcenter Defaultcenter] removeobserver:_observer];
- }
- }
In the code above, we add an observer to the notification hub and then release the registration at Dealloc, and everything looks normal. But here are two questions:
1.) In the message notification block referenced to self, where the Self object is block retain, and _observer retain a copy of the block, Notification Center and hold _observer. So as long as the _observer object has not been de-registered, the block will be held by the Notification center, so that self will not be freed and its dealloc will not be invoked. And we expect to removeobserver in Dealloc to remove the notification center from the _observer/block retain.
2.) At the same time, _observer is defined as an assignment in the Self's class, and therefore is self retain, thus forming a circular reference.
The above procedure 1) deserves an in-depth analysis:
The block variables in AddObserverForName:object:queue:usingBlock: In Apple's official document are described below:
The block is copied by the Notification center and (the copy) held until the observer registration is removed.
Therefore, the notification center copies the block and holds the copy until the _observer registration is released. In ARC, the block will retain self, either directly referencing self or by referencing the member variable of self, in the block being copied.
These two problems can be solved with Weak–strong dance technology. This technique was introduced in the WWDC: WWDC Session #322 (objective-c advancements in Depth)
[OBJC]View Plaincopy
- __weak Ksviewcontroller * wself = self ;
- _observer = [[Nsnotificationcenter Defaultcenter]
- addobserverforname:@ "Testnotificationkey"
- Object: Nil queue: nil usingblock:^ (nsnotification *n) {
- Ksviewcontroller * sself = wself;
- if (sself) {
- NSLog (@ "%@", sself);
- }
- else {
- NSLog (@ "<self> Dealloc before we could run this code.");
- }
- }];
Let's analyze why this technique works.
First, a weak reference to self is defined before the block wself, because it is a weak reference, so wself becomes nil when Self is freed, and then references the weak application in the block, taking into account the multithreaded case, by referencing the weak reference by using the strong reference self. If self is not nil at this point, self is retain to prevent self from being freed during subsequent use, and then the strong reference self is used in subsequent block blocks, noting that the self is nil detected before use because of the weak reference ws in a multithreaded environment When the elf assigns a strong reference to a sself, the weak reference wself may already be nil.
In this way, the block does not hold the self reference, thus breaking the circular reference
How to avoid circular references in block