IOS Block Circular reference explaining

Source: Internet
Author: User

Preface a circular reference is when self owns a block, and the method of self is called in block. Form you have me, I have you, who can not release who the dilemma. or the solution in short, just one thing: __weak typeof (self) weakself = self;

This article explaining the use of block in iOS development must be aware of memory management issues, it is easy to create circular references. The goal of this article is to help you quickly master the skill of using block.

I believe that we all feel that using block to develop a lot of convenience, but there are many developers of block memory management is not good enough, resulting in frequent circular reference problems. For the novice, there is a circular reference, it is difficult to find, so through the leaks may not be able to detect, more important or to rely on their own analysis to infer.

Sound Scene One: The controller is passed between the block value

Now, we declare two controller classes, one called Viewcontroller and the other called Hybacontroller. Where Viewcontroller has a button that will push to hybacontroller when clicked.

First Look at Hybacontroller:

1234567 Disclosed a Method-(Instancetype) Initwithcallback: (Hybcallbackblock) callback; The non-public attributes, which are put out here just to tell you that Hybacontroller will be strong on this attribute reference @property (nonatomic, copy) Hybcallbackblock Callbackblock;

Here are a few small scenarios to look at circular reference issues:

1234567891011121314151617181920 @interface Viewcontroller ()//reference button just to test @property (nonatomic, strong) UIButton *button;//just to test the memory problem, refer to it. In the development, there are many times we are//need to refer to another controller, so here simulation. @property (nonatomic, strong) Hybacontroller *VC; @end//Click Button-(void) GoToNext {Hybacontroller *VC = [[Hybacontroller alloc] initwithcallback:^{[Self.button sett  Itlecolor:[uicolor Greencolor] forstate:uicontrolstatenormal];  }];  SELF.VC = VC; [Self.navigationcontroller PUSHVIEWCONTROLLER:VC animated:yes];}

Now look Viewcontroller here, here in the block where the circular reference is formed, so the VC attribute is not released. Analyze the reason why it forms a circular reference (for example):

To put it simply, two rings are formed here:

    • Viewcontroller-> strongly references the attribute vc-> strongly references the callback-> strong reference to the Viewcontroller
    • The viewcontroller-> strongly references the attribute vc-> strongly references the Callback-> strongly referenced property of the Viewcontroller button

For this problem, we want to solve the memory loop reference problem, we can do this:

The VC attribute is not declared or the VC attribute is declared as a type of weak reference, in callback back to the mediation, the Self.button changed to Weakself.button, that is, callback this block to Viewcontroller to a weak reference. If it is changed to the following, the memory can be released normally:

12345678910 -(void) GoToNext {__weak __typeof (self) weakself = self; Hybacontroller *VC = [[Hybacontroller alloc] initwithcallback:^{[Weakself.button settitlecolor:[uicolor GreenColor] fo  Rstate:uicontrolstatenormal];  }];//self.vc = VC; [Self.navigationcontroller PUSHVIEWCONTROLLER:VC animated:yes];}

I tried to use leaks to detect memory leaks, but all through, a green tick, let you think the memory processing is very good, and actually the memory is not released.

For this scenario, give us some suggestions:

    • Print logs in the controller's lifecycle Viewdidappear:

1234567 -(void) Viewdidappear: (BOOL) animated {[Super viewdidappear:animated]; NSLog (@ "Enter Controller:%@", [[Self class] description]);}

    • Print logs in the controller's lifecycle Dealloc:

12345 -(void) Dealloc {NSLog (@ "Controller is dealloc:%@", [[Self class] description]);}

This way, as long as the log does not print out, indicating that the memory is not released, you need to learn to analyze the memory reference problem.

Scenario Two: Block value between Controller and view

Let's start by defining a view to interact with the controller. When the View button is clicked, it is passed to the controller by the block callback, and the corresponding data is passed to the controller to record:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546  typedef void (^hybfeedbackblock) (ID model);  @interface hybaview:uiview -(instancetype) Initwithblock: (hybfeedbackblock) block;  @end   @interface Hybaview ()   @property (nonatomic, copy) Hybfeedbackblock block;  @end   @implementation hybaview -(void) Dealloc {  nslog (@ "Dealloc: %@ ", [[Self class] description]);}  -(Instancetype) Initwithblock: (hybfeedbackblock) block {  if (self = [super init]) {     self.block = Block;        uibutton *button = [UIButton buttonWithType : Uibuttontypecustom];    [button settitle:@ "Feedback to Controller" Forstate:uicontrolstatenormal];     button.frame = CGRectMake (A.     button.backgroundcolor); [Uicolor Redcolor];    [button Settitlecolor:[uicolor Yellowcolor] ForState: Uicontrolstatenormal];    [button addtarget:self Action: @selector (feedback) forcontrolevents:uicontroleventtouchupinside];    [self AddSubview:button];   }    return self;}  -(void) Feedback {  if (self.block) {    //Pass the model back, there is no data, assuming nil     self.block (nil);  }}  @end  

Next look at Hybacontroller, which adds two properties, and when Viewdidload, creates the Aview property:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748   @interface Hybacontroller ()   @property (nonatomic, copy) Hybcallbackblock callbackblock;  @property ( Nonatomic, Strong) Hybaview *aview, @property (nonatomic, strong) ID currentmodel;  @end   @implementation hybacontroller -(Instancetype) Initwithcallback: (Hybcallbackblock) Callback {  if (self = [super init] {    self.callbackblock = Callback;  }    return self;}  -(void) viewdidload {  [super viewdidload];    self.title = @ "HYBAController";   self.view.backgroundcolor = [Uicolor Whitecolor];    self.aview = [[HYBAView alloc] initwithblock:^ (ID model) {    //assumes to update model    self.currentmodel = model;   }];  //assume full screen   self.aview.frame = Self.view.bounds;  [self.view Addsubview:self.aview];  self.aview.backgroundcolor = [Uicolor whitecolor];}  -(Void) Viewdidappear: (BOOL) Animated {  [super Viewdidappear:animated];    nslog (@ " Enter controller:%@ ", [[Self class] description]);}  -(void) Dealloc {  nslog (@ "Controller is dealloc:%@", [[Self class] description]);}   @end  

The circular reference to the previous scenario has been resolved, so the focus of this section is on the controller and view reference issues.

Analysis: As shown in:

The rings are formed by:

    • VC->AVIEW->BLOCK->VC (self)
    • Vc->aview->block->vc.currentmodel

The solution can be: When creating Aview, the reference to Currentmodel in the block is changed to a weak reference:

1234567 __weak __typeof (self) weakself = Self;self.aview = [[Hybaview alloc] initwithblock:^ (ID model) {//Suppose to update model Weaks Elf.currentmodel = model;}];

I've seen a lot of code like this, directly using member variables instead of attributes, and then they thought that it would not refer to self, which is the controller, thus not forming a ring:

123456 Self.aview = [[Hybaview alloc] initwithblock:^ (ID model) {//Suppose to update model _currentmodel = model;}];

This is a false understanding that when we refer to _currentmodel, it is a member variable of the controller and therefore references the controller. To resolve this issue, you also want to change to a weak reference:

1234567 __block __weak __typeof (_currentmodel) Weakmodel = _currentmodel;self.aview = [[Hybaview alloc] initWithBlock:^ (ID model {//Assume to update model Weakmodel = model;}];

Here also add __block Oh!

Simulating a circular reference

Suppose the following code is written, is there a problem with memory not being released? (where the Controller property is a strongly-referenced declaration)

12345678 @autoreleasepool {a *AVC = [[a alloc] init];  b *BVC = [[B allcok] init];  Avc.controller = BVC; Bvc.controller = AVC;}

Analysis:

    • Avc-> a strong reference to BVC
    • Bvc-> a strong reference to AVC

If this is the case, it forms a ring. AVC->BVC->AVC, this forms the ring.

See if it forms a ring

1234567 Nsmutablearray *marray = [Nsmutablearray arraywithobjects:@ "a", @ "B", @ "abc", nil]; Hybacontroller *VC = [[Hybacontroller alloc] initwithcallback:^{[Marray removeobjectatindex:0];}]; [Self.navigationcontroller PUSHVIEWCONTROLLER:VC Animated:yes];

    • VC--strong reference block
    • Block-> a strong reference to MyArray

Therefore, there is no ring formed.

If the myarray is strongly referenced to the current controller, it does not form a ring:

    • VC--strong reference block
    • Block-> Strong reference to self (current controller)

A circular reference is formed if the VC is set to the SELF.VC attribute and is a strong reference.

Written in the last

This article is about so much, writing an article is to teach you how to analyze whether the memory is formed ring, as long as you know how to analyze the memory is a circular reference, then in the development of special attention to memory management problems, and find memory-related problems when the bug, it is also easier.

IOS Block Circular reference explaining

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.