Ios-three scenarios that can easily cause circular references

Source: Internet
Author: User

ARC has been out for a long time, it is really convenient to automatically release the memory, but not absolute security will never create a memory leak. An invisible killer that causes iOS objects to not be released as expected is a circular reference. A circular reference can be simply understood as a refers to B, and B refers to a, both sides hold a reference to each other at the same time, resulting in any time the reference count is not 0, and cannot be released at all times. If the current object is a Viewcontroller, the dealloc cannot be called after dismiss or pop, and the memory bursts after frequent push or present, and then the app is Duang to hang. Here are the three types of circular references that we have become more susceptible to.

(1) Timer Nstimer

On the one hand, Nstimer is often used as a member variable for a class, while Nstimer is initialized to specify self as target, which can easily cause circular references. On the other hand, if the timer is always in the validate state, its reference count will always be greater than 0. Let's look at an example of Nstimer use (ARC mode):

1 #import <foundation/foundation.h>2 @interface friend:nsobject3-(void) cleantimer;4 @end
1 #import "Friend.h"
2 @interface Friend () 3 {4     Nstimer *_timer; 5} 6 @end 7  8 @implementation Friend 9-(ID) init10 {one-by-one     (sel f = [Super init]) {         _timer = [Nstimer scheduledtimerwithtimeinterval:1 target:self selector: @selector (Handletimer :)                                                 userinfo:nil repeats:yes];14     }15     return  self;16}17-(void) Handletimer: (ID) sender19 {20     NSLog (@ "%@ say:hi!", [Self class]),}22-(void) cleanTimer23 {     [_timer invalidate];25     _timer = nil;26} (void) Dealloc28 {     [self cleantimer];30     NSLog (@ "[Friend class] is dealloced"); 31}

Initializes a friend object outside the class and releases the friend after 5 seconds of delay (externally running in a non-arc environment)

1         friend *f = [[Friend alloc] init];2         dispatch_after (Dispatch_time (Dispatch_time_now, 5*nsec_per_sec), Dispatch_get_main_queue (), ^{4             [f release];5         });

The result we expect is that after 5 seconds of initialization, the F object is called by the Dealloc method of the Release,f, and in Dealloc the timer expires and the object is refactored. But the result is this:

12345678910 2015-03-18 18:00:35.300 WZLCodeLibrary[41422:3390529] Friend say: Hi!2015-03-18 18:00:36.299 WZLCodeLibrary[41422:3390529] Friend say: Hi!2015-03-18 18:00:37.300 WZLCodeLibrary[41422:3390529] Friend say: Hi!2015-03-18 18:00:38.299 WZLCodeLibrary[41422:3390529] Friend say: Hi!2015-03-18 18:00:39.299 WZLCodeLibrary[41422:3390529] Friend say: Hi!//运行了5次后没按照预想的停下来2015-03-18 18:00:40.299 WZLCodeLibrary[41422:3390529] Friend say: Hi!2015-03-18 18:00:41.300 WZLCodeLibrary[41422:3390529] Friend say: Hi!2015-03-18 18:00:42.300 WZLCodeLibrary[41422:3390529] Friend say: Hi!2015-03-18 18:00:43.299 WZLCodeLibrary[41422:3390529] Friend say: Hi!2015-03-18 18:00:44.300 WZLCodeLibrary[41422:3390529] Friend say: Hi!<br>.......根本停不下来.....

What is this for? Mainly because from the point of view of the timer, the timer thinks that the caller (Friend object) will enter the Dealloc when it is refactored, and in Dealloc can stop the timer's timing and release the memory, but from friend's point of view, he thinks that the timer does not stop the timing, Then I never got a chance to get into dealloc. Circular references, waiting for each other, the descendants of the endless also. The crux of the problem is that-(void) The invocation of the Cleantimer function is not opportune, and obviously cannot be placed in the caller's dealloc. A good solution is to open this function and let friend's caller explicitly invoke it to clean up the scene. As follows:

12345 Friend *f = [[Friend alloc] init];dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5*NSEC_PER_SEC), dispatch_get_main_queue(), ^{    [f cleanTimer];    [f release];});

=======================================

(2) block

Block uses a strong reference (ARC) or Retaincount 1 (non-ARC) for the objects used inside the block at copy time. Improper use of blocks in both arc and non-ARC environments can cause circular reference problems, generally shown by a class that uses block as its own property variable, and then the class itself in the block's method body, which is simply self.someblock = ^ (Type var) {[Self dosomething]; or self.othervar = XXX; or _othervar = ...}; This circular reference to the block is captured by the compiler and alerted in a timely manner. For example, the friend class is still an example of this:

#import "Friend.h"
@interface Friend () @property (nonatomic) Nsarray *arr; @end @implementation friend-(ID) init{    if (self = [super init]) {         Self.arr = @[@111, @222, @333];        Self.block = ^ (NSString *name) {            NSLog (@ "arr:%@", Self.arr);        };    }    return self  ;}

We see that the arr attribute of the friend class is used inside the block implementation, and Xcode gives the warning, and after running the program proves that the friend object cannot be refactored:

Most of the online posts are expressed as "self causes circular references in block," but is that really the case? I doubt that such a statement is not rigorous, and it does not necessarily mean that the word "self" should be explicitly used to induce circular references. Instead of accessing the ARR variable through the property Self.arr, we change the code to access it through the instance variable _arr, as follows:

As a result we know that even if "self" is not explicitly present in your block code, a circular reference will appear! As long as you use the self-possessed thing in the block ! In this case, however, we cannot use the __weak declaration or the __block Declaration to prohibit a block from strongly referencing self or to force an increase in the reference count. But we can avoid circular references through other pointers (thanks to Xq_120 's reminders), specifically:

12345 __weak typeof(self) weakSelf = self; self.blkA = ^{__strong typeof(weakSelf) strongSelf = weakSelf;//加一下强引用,避免weakSelf被释放掉 NSLog(@"%@", strongSelf->_xxView); //不会导致循环引用.};

For the Self.arr situation, we need to divide into two kinds of environment to solve:

1) Arc Environment: In the ARC environment, you can use _weak to declare a new variable instead of self, which we can name as weakself. In this way, tell block not to force the self in the Block strong reference: (if you want to be compatible with ios4.3, then use __unsafe_unretained instead of __weak, but for the time being basically do not need to consider such a low version)

1          self.arr = @[@111, @222, @333];2         __weak typeof (self) weakself=self;3         self.block = ^ (NSString *name) {4             NSLog (@ "arr:%@", Weakself.arr); 5         };

2) under the MRC Environment: the solution is basically the same as above, but the __weak keyword can be replaced with __block, so the meaning is to tell block: Boy, do not in-house to self retain!

=========================================================

(3) Entrusted delegate

There is a circular reference issue on the delegation issue is a cliché, this article is no longer detailed, to avoid the problem of the killer is also simple to cry, a word tactic: declare delegate when you use assign (MRC) or weak (ARC), do not hand the cheap play retain or strong, After all, this basically can't escape the circular reference!

This blog is reproduced in the programming Little Weng @ Blog Park, Mail [email Protected],jilon, Original: http://www.cnblogs.com/wengzilin/p/4347974.html

Ios-three scenarios that can easily cause circular references

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.