[Circular reference of the block under arc in]ios

Source: Internet
Author: User

"Features of Arc "

Under Arc, all nsobject type pointers,

1. Default is __strong type

2. The specified __weak type can be displayed, and the __weak type pointer is automatically set to nil when the pointing object is destroyed

3. __autorelesing type for inout parameter type

Under Arc, when a function returns a nsobject pointer, the compiler will help us implement the autorelease call. For example:

return pobject;

The compiler will help us extend to return [Pobject autorelease];

Under ARC, you cannot explicitly release, you can use the value of nil to let the compiler release for us.

"Arc and Block"

The life cycle management of blocks is very subtle and more complex when mixed with arc.

The compiler adds [[Copy] autorelease] code when the block is passed up in the stack (up) and is returned directly.

The [^{} Copy] method needs to be explicitly called when the block extension stack is passed down to a container that requires retain.

Under Arc, the NSObject pointer modified by __block will still be retain.

Under Arc, when an instance variable of an object is referenced within a block, self is retain, so it is very easy to cause strong reference cycle, which can be avoided by __weak pointers, because ARC does not __weak for retain pointers.

After iOS4.0 launched the blocks language feature,
By now, iOS has reached 5.0.
So I think blocks should be able to be used by the pan.
But now the iOS environment is going from MRC (Manual Reference counting) to Arc (Automatic Reference counting)
In the reference counting environment, runtime is not self-releasing retain cycle.
And blocks has a lot of hidden retain.
It is easy to accidentally cause retain cycle.
And the focus of this article is to point out three anti-patterns that will cause retain cycle
Let's talk a little bit about how to solve it.

Before the discussion, we'll probably recap some concepts.
Block is allowed to use the external variable
But local variable is a self-made retain.
For example

myclass* foo = ...; self.someblock = ^{    [foo bar];};

When the above foo is copied to the heap in this block
will be retain with the self.
And that's what I'm saying is that it's easy to cause retain cycle.


Anti Pattern 1
For the first example, let's use the Opne Source Library asihttprequest as a sample
Look at the following example, is there any problem?

ASIHTTPRequest *request = [ASIHTTPRequest Requestwithurl:url]; [Request setcompletionblock:^{    //Use when fetching text data    nsstring *responsestring = [Request responsestring ];    Use when fetching binary data    nsdata *responsedata = [request ResponseData];}];

The first thing we need to be aware of here is [request setCompletionBlock:…] this
The obvious use of this side is to do an event callback use
That is to say I give you a block, when the action is done callback me.
This is a typical non-synchronous approach.
But because if you're going to use it after the block is taken,
You must call [aBlock copy] the action,
This action will drop the block from the stack heap.
Because the environment block in iOS is also an object,
This block's retain count will increase by 1.
At this time, according to the definition, this local change in the Block request will also be retain.
So request the retain count will also increase by 1.
But the question is, once the task request is completed, it should be release.
It will be discovered that retain count will not be zero. Reason is
Request <-> block These two retain each other.
Without normal release, this is called the retain cycle.

The solution is simple, look at the ASIHTTPRequest official web file.
Which is used to __block describerequest

__block asihttprequest *request = [ASIHTTPRequest Requestwithurl:url]; [Request setcompletionblock:^{    //Use when fetching text data    nsstring *responsestring = [Request responsestring ];     Use when fetching binary data    nsdata *responsedata = [request ResponseData];}];

Through block variable not retain features,
A bit like weak reference's role
The block will not retain at this time.request
Of course there is no question of retain cycle.


Anti Pattern 2
Anti Pattern 1 is easy to show when using someone's library.
Anti Pattern 2 is easy to appear when you are actually doing your class.
Please see the code below

Myclass.h@property <nonatomic, copy= "" > Myblock oncompleteblock;//myclass.cself.oncompleteblock = ^{    [ Self dosomething];}

I believe this is where the problem is.
In fact, anti Pattern2 is considered a special case of anti Pattern 1.
It's just that the special variables are used here.

But sometimes we are more likely to overlook the beginning of our own member in the block variable
For example

Myclass.h@interface myclass:nsobject{    nsdate* lastmodifed;} MyClass.cself.onCompleteBlock = ^{    lastmodifed = [[NSDate date] retain];}

It's not that easy to feel at this time.
According to the definition, when using block,
If we use the member variable,
This time retain is not lastmodified refers to the object
But retain self .
So the result is
Self <-> block retain each other
The result of anti pattern 11 is that it is impossible to finally release memory.

The solution at this time is also to take out __block

Myclass.c__block myclass* tempself = Self;self.oncompleteblock = ^{    tempself.lastmodifed = [NSDate date];}


Anti Pattern 3
Continue to look at the following code

settingsviewcontroller* Settingsviewcontroller =    [[[[Settingsviewcontroller alloc] init] autorelease]; Settingsviewcontroller.onupdate = ^{    [self doupdate];} Self.settingsviewcontroller = Settingsviewcontroller;

Although there is no direct use of settingsviewcontroller in this block, there is no retain cycle
But because self---Settingsviewcontroller
and Block Setttingsviewcontroller
Next Block--Self
It's just a circle and there's a retain cycle.

So, still want to use anti pattern 2 solution to solve

rootviewcontroller.msettingsviewcontroller* Settingsviewcontroller =    [[[[Settingsviewcontroller alloc] init] Autorelease];__block rootviewcontroller* tempself = self;settingsviewcontroller.onupdate = ^{    [tempSelf doUpdate] ;} Self.settingsviewcontroller = Settingsviewcontroller;

In the reference counting environment,
I suggest that the best way to resolve retain cycle is to think clearly about the relationship
For example, the last anti pattern
Their relationship should be
block, Settingsviewcontroller, Rootviewcontroller
If the block is going to use Settingsviewcontroller or Rootviewcontroller,
It is necessary to use weak reference (i.e. __block )
Under such a principle, you can know which retain to give to him.

The last thing to fill is that the example above is in the MRC environment.
Variable in the MRC __block is not retain when used in a block.
But the arc __block will be retain.
Instead, use __weak or __unsafe_unretained more accurately describe the purpose of weak reference.
The former can only be used after iOS5, but it is better (after the object is release, this pointer will be set to nil automatically)
The latter is the arc of the environment for a compatible 4.x solution.
So in the example above,

__block myclass* temp = ...;    MRC Environment using __weak myclass* temp = ...;    ARC but only supports versions above iOS5.0 __unsafe_retained myclass* temp = ...;  Arc and can be compatible with 4.x later versions

--------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------- ---------

Block is a special block of code that can capture context. Blocks can access variables defined outside the block, and when used in a block, it creates a copy of each scalar variable within the scope. If you have a block by self and then change the instance variable in the block, you will get an error. For example:
1 Self.block = ^ (NSString *astring) 2 {3     self.aLabel.text = astring;4});

In this code, self retains the block, and the block retains self, triggering a circular hold. It's dangerous. If you do not use arc, you can use __block and __unsafe_unretained to copy an unreserved reference copy.
1//For example: (no arc) 2 __block id safeself = self; 3 Self.block = ^ (NSString *astring) 4 {5     safeSelf.aLabel.text = astring; 6}); 7   8//(with ARC) 9 __weak id safeself = self;        iOS 510//__unsafe_unretained id safeself = self; iOS 411 Self.block = ^ (NSString *astring) {     safeSelf.aLabel.text = astring;14});
Before the arc appears, we are free to turn the Cf* object into a Ns* object, which is called self-bridging. After using arc, we need to specify a title transfer modifier. The modifiers currently available in Arc are: 1.__bridge2.__bridge_retained3.__bridge_transfer The first modifier __bridge is a normal conversion, which means that no reference count needs to be added and ownership is not changed. The second is to increase the value of the reference count when converting the C pointer type. The third one is to convert the core Foundation pointer type to the OBJ-C pointer, changing the reference count value to +1. If you create an object with the core Foundation method, and you want to use ARC to manage the memory of the object, you can use this. Common errors with Arc porting 1. Cast obj-c pointer bit c pointer (or vice versa) 2. Forces the void* pointer to the ID type (or vice versa) in arc, if you want to go, you must use a modifier such as: id selfpointer = (__bridge void *) self;3. In the struct or (Union) assembly body is the Obj-c object 4. Using NSAutoreleasePool to: http://blog.csdn.net/a330416020/article/details/19119491

[Circular reference of the block under arc in]ios

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.