Write to a friend who likes to block (iOS block)

Source: Internet
Author: User
Tags call back

fengsh998Original address:http://blog.csdn.net/fengsh998/article/details/38090205 Reprint Please indicate the source If you feel that the article is helpful to you, please leave a message or pay attention to the public account fengsh998 to support me, thank you!


This article does not talk about how blocks are declared and used, only the hidden dangers that the block encounters and poses in the course of use.

The demonstration is based on two main points:

Circular reference of 1.block (retain cycle)

2. When removing the alarm from block, you should pay attention to the problem.


Once, my friend asked me when a block in an object's access to its own property will cause a circular reference, I'm going to go back to a sentence, not. Brother, after reading this, I hope you can understand why I would say no circular references. Stop talking nonsense and start the demo.


Here are some of the classes that I have written to demonstrate:

Header file. h

blockdemo.h//blockdemo////Created by Apple on 14-7-24.//Copyright (c) 2014 FENGSH.  All rights reserved./*-fno-objc-arc because the block is built on the stack by default, so if you leave the method scope, the block will be discarded, in the non-arc case, we want to return a block, need [Block copy]; Under Arc, the block is automatically copied from the stack to the heap: 1. Executed copy Method 2. The value returned as a Method 3. Assigns a block to a class with an ID type with the __strong modifier or blcok type member variable 4. When the method name contains the Usingblock cocoa framework method or the GDC API is passed. */#import <Foundation/Foundation.h> @class blockdemo;typedef Void (^executefinishedblock) (void); typedef void (^    Executefinishedblockparam) (Blockdemo *); @interface blockdemo:nsobject{Executefinishedblock Finishblock; Executefinishedblockparam Finishblockparam;} /** * Execution Results */@property (nonatomic,assign) Nsinteger resultcode;/** * Each call produces a new object * * @return */+ (Blockdemo *) Blockdem o;/** * block with no parameters * * @param block */-(void) setexecutefinished: (Executefinishedblock) block;/** * block with parameters * * @para M block */-(void) Setexecutefinishedparam: (Executefinishedblockparam) block;-(void) executetest; @end

Implementation file

blockdemo.m//blockdemo////Created by Apple on 14-7-24.//Copyright (c) 2014 FENGSH. All Rights reserved.//#if __has_feature (objc_arc) && __clang_major__ >= 3 #define objc_arc_enabled 1#endif/            /__has_feature (OBJC_ARC) #if objc_arc_enabled #define Objc_retain (object) #define Objc_copy (object) (object) #define Objc_release (object) object = Nil #define Objc_autorelease (object) #el SE #define Objc_retain (object) [object RETAIN] #define OBJC_COPY (object) [Object COPY] #def Ine Objc_release (object) [Object RELEASE], object = Nil #define Objc_autorelease (object) [Object Autorele ASE] #endif #import "BlockDemo.h" @implementation blockdemo+ (Blockdemo *) blockdemo{return objc_autorelease ([[ Blockdemo alloc]init]);}    -(ID) init{self = [super init];    if (self) {NSLog (@ "Object constructor!");} return self;} -(void) dealloc{NSLog (@ "Object destoryed!"); #If!__has_feature (OBJC_ARC) [Super Dealloc]; #endif}-(void) setexecutefinished: (executefinishedblock) block{Objc_rel    EASE (Finishblock); Finishblock = objc_copy (block); You cannot use retain}-(void) Setexecutefinishedparam under non-arc: (Executefinishedblockparam) block{objc_release (    Finishblockparam); Finishblockparam = objc_copy (block); Under non-ARC cannot use retain}-(void) executetest{[self performselector: @selector (executecallback) Withobject:nil Afterdelay:5];}        -(void) executecallback{_resultcode = 200;    if (finishblock) {finishblock ();    } if (Finishblockparam) {finishblockparam (self); }} @end

The above is due to the fact that I have made an arc precompiled decision in the light of the compilation demonstration in Arc and non-arc. It is mainly convenient not to change too much code to show you.


In non-ARC environments


Perform the following test on the statement:

-(Ibaction) OnTest: (ID) sender{    blockdemo *demo = [[[Blockdemo alloc]init]autorelease];        [Demo setexecutefinished:^{        if (Demo.resultcode = =) {            NSLog (@ "Call back OK.");        }    ];        [Demo executetest];     }

Output Result:

2014-07-24 19:08:04.852 blockdemo[25104:60b] Object constructor!2014-07-24 19:08:09.854 blockDemo[25104:60b] Call back Ok.

It's obvious. Although the demo is a local variable and autorelease, it can be seen that the nature has not been released because the block has access to its own ResultCode attribute within the block. I believe many friends will also solve this circular reference problem. is to put a __block in front of the variable, like this.

__block Blockdemo *demo = [[Blockdemo alloc]init]autorelease];
Under the non-arc, only a __block keyword can be. It's relatively simple.

OK, here's a look at the Block circular reference in ARC mode.

In Arc mode

Execute the following statement:

-(Ibaction) OnTest: (ID) sender{    blockdemo *demo = [[Blockdemo alloc]init];    [Demo setexecutefinished:^{        if (Demo.resultcode = =) {            NSLog (@ "Call back OK.");        }    ];        [Demo executetest];     }

Execution output:

2014-07-24 19:20:33.997 blockdemo[25215:60b] Object constructor!2014-07-24 19:20:39.000 blockDemo[25215:60b] Call back Ok.
will also be introduced into the loop.

Believe to see the people here, most of them to spray, which do not know Ah, but also know how to solve, non-arc added a __block, of course, in the arc plus a __weak to be done. Well, that's true, but don't worry, and then look down, there's definitely a harvest. First of all, here you think about how you add this __weak.

For the first question is the circular reference of the DOT block (retain cycle) here to the end. Let's talk about 2nd. Because the block alarm is not found in the non-arc in the introduction of the writing (if you know, trouble tell me how to generate alarm, I am good to study.) )

Here are some things to watch out for in arc mode, except for the alarms that are generated by the notation.

The notation above is actually generated in the arc (capturing ' demo ' strongly in this block are likely to leads to a retain cycle) alarm. Such as:


In Arc, the compiler is intelligent, and a direct prompt to write this will produce a circular reference. So a lot of love to remove the alarm of friends will be the idea of removing, good, let me look at the removal of the need to pay attention to the problem.

Situation One:

-(Ibaction) OnTest: (ID) sender{    __weak Blockdemo *demo = [[Blockdemo alloc]init];    [Demo setexecutefinished:^{        if (Demo.resultcode = =) {            NSLog (@ "Call back OK.");        }    ];    [Demo executetest];}
Add a __weak directly to the front, but does it really have no alarms? If there is, which Shangong like you, explain that the compiler also help you a big favor. See



This will also alarm, said this is a weak variable, will be release immediately. Therefore, the contents of the block are not executed. Everyone can run a look

The output is:

2014-07-24 19:38:02.453 blockdemo[25305:60b] Object constructor!2014-07-24 19:38:02.454 blockDemo[25305:60b] Object destoryed!
It was clear that the code in the block would not be executed at all immediately.

Thankfully, the compiler told us in advance that there was this hidden danger. I believe that everyone to solve the alarm, and will get a more complete solution, see below:

-(Ibaction) OnTest: (ID) sender{    blockdemo *demo = [[Blockdemo alloc]init];        __weak typeof (Blockdemo) *weakdemo = demo;        [Demo setexecutefinished:^{        if (Weakdemo.resultcode = =) {            NSLog (@ "Call back OK.");        }    ];    [Demo executetest];}

In this way, the alarm is removed and the block is guaranteed to operate. That's what we want to end up with.
The output is:

2014-07-24 19:40:33.204 blockdemo[25328:60b] Object constructor!2014-07-24 19:40:38.206 blockDemo[25328:60b] Call back ok.2014-07-24 19:40:38.207 blockdemo[25328:60b] Object destoryed!

But let's not be complacent. There are hints, I believe everyone can deal with, and get a good solution. The next big to look at this writing, let you really beats me ...

-(Ibaction) OnTest: (ID) sender{    __weak Blockdemo *demo = [Blockdemo Blockdemo];//Here is the point, Front is [[Blockdemo Alloc]init] ; there will be alarms.        [Demo setexecutefinished:^{        if (Demo.resultcode = =) {            NSLog (@ "Call back OK.");        }    ];    [Demo executetest];}


Actually just put Init in the class method to write it, but it will be different.
+ (Blockdemo *) blockdemo{    return Objc_autorelease ([[Blockdemo alloc]init]);}
Different points see: Really do not see what alarm, is not. But what is the risk, the risk is that when running, block simply does not run. Because the object was already released.


Direct output:

2014-07-24 19:47:53.033 blockdemo[25395:60b] Object constructor!2014-07-24 19:47:53.035 blockDemo[25395:60b] Object destoryed!

Therefore, write this is mainly used to tell some people like to use block but also for a while, some friends like to remove the alarm, but only blindly add __weak or __block key words, often there are some major security risks. Just like the demo, Block doesn't go at all. If the release, in order to go to alarm and so simple processing, and did not test the package. Which is going to die badly ...


Well, to the end, to say why my friend asked me if block will lead to the death cycle, I said no reason.

See Code:

-(Ibaction) OnTest: (ID) sender{    blockdemo *demo = [Blockdemo blockdemo];//[[blockdemo alloc]init];        [Demo setexecutefinishedparam:^ (Blockdemo * ademo) {        if (Ademo.resultcode = =) {            NSLog (@ "Call back OK.");        }    ];        [Demo executetest];}

Whether it's outside the init, or inside, without adding __block and __weak. Why, because I personally often use my own block, if it is a callback, I prefer to think of itself as a parameter to the block. This is the fact that the compiler gave us a weak reference. Therefore, circular references are not generated.

Since I've been writing blocks like this all along, so when my friend asks, I say I'm not going to loop, because what he's been through is the kind of access that I've been talking about, and I'm answering the way I use it. Because of the verbal description, and the actual response is really bad miles ... Ha ha. In order to verify my friend's this, I specially wrote this article, hoped to be helpful to everybody. Finally, thank you all for taking the time to read.












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.