To friends who like to use Block (ios Block)

Source: Internet
Author: User

To friends who like to use Block (ios Block)

Author: fengsh998 Original article address: workshop!


This article does not explain how block is declared and used. It only describes the hidden dangers that block encounters during use.

The demo is based on two points:

1. retain cycle)

2. When removing block alarms, pay attention to the issues.


Once, my friend asked me if the access to my own attributes in the block of an object will cause a circular reference. I just replied, No. After reading this, I hope you can understand why I say I won't reference it cyclically. Don't talk nonsense. The demo starts.


Below is a class we have written for Demonstration:

Header file. h

//// BlockDemo. h // blockDemo /// Created by apple on 14-7-24. // Copyright (c) February 11, 2014 fensh. all rights reserved. /*-fno-objc-arc because the Block is built on the stack by default, the Block will be discarded if it leaves the method scope. In non-ARC scenarios, to return a Block, we need [Block copy]. In ARC, the Block will be automatically copied from the stack to the heap in the following situations: 1. copy method 2. return Value as method 3. when a Block is assigned to a class or Blcok member variable of the id type with the _ strong modifier 4. when the method name contains the usingBlock Cocoa framework method or gdc api is passed. */# import
 
  
@ Class BlockDemo; typedef void (^ executeFinishedBlock) (void); typedef void (^ Queue) (BlockDemo *); @ interface BlockDemo: NSObject {executeFinishedBlock finishblock; Define finishblockparam ;} /*** execution result */@ property (nonatomic, assign) NSInteger resultCode;/*** each call generates a new object ** @ return */+ (BlockDemo *) blockdemo;/*** block without parameters ** @ param block */-(void) setExecuteFinished :( executeFinishedBlock) block; /*** block with parameters ** @ param block */-(void) setExecuteFinishedParam :( executeFinishedBlockParam) block;-(void) executeTest; @ end
 

Implementation File

//// BlockDemo. m // blockDemo /// Created by apple on 14-7-24. // Copyright (c) February 11, 2014 fensh. 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) # define OBJC_RELEASE (object) object = nil # define OBJC_AUTORELEASE (object) # Else # define OBJC_RETAIN (object) [object retain] # define OBJC_COPY (object) [object copy] # define OBJC_RELEASE (object) [object release], object = nil # define OBJC_AUTORELEASE (object) [object autorelease] # endif # import "BlockDemo. h "@ implementation BlockDemo + (BlockDemo *) blockdemo {return OBJC_AUTORELEASE ([[BlockDemo alloc] init]);}-(id) init {self = [super init]; if (self) {NSLog (@ "Object Construct Or! ");} Return self;}-(void) dealloc {NSLog (@" Object Destoryed! "); # If! _ Has_feature (objc_arc) [super dealloc]; # endif}-(void) setExecuteFinished :( executeFinishedBlock) block {OBJC_RELEASE (finishblock); finishblock = OBJC_COPY (block ); // In non-ARC scenarios, retain}-(void) setExecuteFinishedParam :( executeFinishedBlockParam) block {OBJC_RELEASE (finishblockparam); finishblockparam = OBJC_COPY (block ); // retain}-(void) executeTest {[self defined mselector: @ selector (executeCallBack) withObject: nil afterDelay: 5];}-(void) cannot be used in non-ARC scenarios) executeCallBack {_ resultCode = 200; if (finishblock) {finishblock ();} if (finishblockparam) {finishblockparam (self);} @ end

The above is because of the compilation demonstration in ARC and non-ARC, So I specially added the ARC pre-compilation judgment. It is easy not to change too much code for demonstration.


In a non-ARC environment


Run the following statement test:

- (IBAction)onTest:(id)sender{    BlockDemo *demo = [[[BlockDemo alloc]init]autorelease];        [demo setExecuteFinished:^{        if (demo.resultCode == 200) {            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.

Obviously. Although the demo is a local variable with autorelease, it can be seen that it is not released at the end, because the block uses the block to access its own resultCode attribute. I believe many of my friends will also solve this kind of circular reference problem. Add a _ block before the variable, just like this.

__block BlockDemo *demo = [[[BlockDemo alloc]init]autorelease];
In non-ARC scenarios, only one _ block keyword can be used. Relatively simple.

Next, let's take a look at the block loop reference in the ARC mode.

In ARC Mode

Execute the following statement:

- (IBAction)onTest:(id)sender{    BlockDemo *demo = [[BlockDemo alloc]init];    [demo setExecuteFinished:^{        if (demo.resultCode == 200) {            NSLog(@"call back ok.");        }    }];        [demo executeTest];     }

Execution output result:

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.
It will also be introduced into the loop.

I believe that most of the people here will be sprayed. I don't know which one, but I still know how to solve it. Instead of adding a _ block to ARC, of course, add _ weak in ARC to solve the problem. Well, this is indeed the case, but don't worry. Next, let's look at it. It's absolutely rewarding. Here, we will first consider how you add this _ weak by default.

For the first question, the retain cycle of the point block is now over. Next we will talk about the second point. Because block alarms are not introduced in non-ARC statements for the time being (if you know, please tell me how to generate alarms. I will study them .)

The following describes the issues that need to be paid attention to when writing alerts in the ARC mode.

In fact, the above Code generates an alarm in the ARC (Capturing 'Demo' stronugly in this block is likely to lead to a retain cycle. For example:


In ARC, the compiler is intelligent and prompts that circular references will be generated for writing. So a lot of friends who love to remove alarms will get rid of their ideas. Well, let's take a look at the issues that need to be paid attention to when removing alarms.

Scenario 1:

- (IBAction)onTest:(id)sender{    __weak BlockDemo *demo = [[BlockDemo alloc]init];    [demo setExecuteFinished:^{        if (demo.resultCode == 200) {            NSLog(@"call back ok.");        }    }];    [demo executeTest];}
Add a _ weak directly to the front, but is there no alarm? If yes, you may like you, it means the compiler is still very helpful. See



At this time, an alarm will be triggered, saying that this is a WEAK variable, and it will be immediately release. Therefore, the content in the block will not be executed. You can run it for a moment.

Output result:

2014-07-24 19:38:02.453 blockDemo[25305:60b] Object Constructor!2014-07-24 19:38:02.454 blockDemo[25305:60b] Object Destoryed!
Obviously, the code in the block is not executed because it is immediately release.

Fortunately, the compiler told us in advance that there is a hidden danger. We believe that you will receive a more satisfactory solution to solve the issue. For details, see:

- (IBAction)onTest:(id)sender{    BlockDemo *demo = [[BlockDemo alloc]init];        __weak typeof(BlockDemo) *weakDemo = demo;        [demo setExecuteFinished:^{        if (weakDemo.resultCode == 200) {            NSLog(@"call back ok.");        }    }];    [demo executeTest];}

In this way, warnings are removed and block operations are ensured. This is the final result we want.
Output:

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 don't be proud of it. I believe everyone can handle this problem and get a good solution. Next let's take a look at this writing method, so that you can really appreciate it .....

-(IBAction) onTest :( id) sender {_ weak BlockDemo * demo = [BlockDemo blockdemo]; // here is the focus. The previous section is [[BlockDemo alloc] init]; there will be an alarm. [Demo setExecuteFinished: ^ {if (demo. resultCode = 200) {NSLog (@ "call back OK.") ;}}]; [demo executeTest];}


In fact, it is just to put init into the class method for writing, but what is the difference.
+ (BlockDemo *)blockdemo{    return OBJC_AUTORELEASE([[BlockDemo alloc]init]);}
Different Points: You can't really see the alarm, right. But what is the risk? The risk is that the block does not run at all during running. Because the object has been released long ago.


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, this is mainly used to warn friends who like to use BLOCK but take it for granted. Some friends like to remove warnings, but just blindly Add the key words _ weak or _ block, there may be some major security risks. It is like the block does not go in the demo. If it is easy to handle the alarm at the time of release, it will be packed without testing. Which would be terrible .....


Well, at the end, I want to explain why my friend asked me if block would lead to an endless loop. I said no.

See the code below:

- (IBAction)onTest:(id)sender{    BlockDemo *demo = [BlockDemo blockdemo];//[[BlockDemo alloc]init];        [demo setExecuteFinishedParam:^(BlockDemo * ademo) {        if (ademo.resultCode == 200) {            NSLog(@"call back ok.");        }    }];        [demo executeTest];}

No matter whether it is outside init or inside, and NO _ block or _ weak is added. Why, because when I use a block that I write myself, if it is a callback, I prefer to upload myself as a parameter to the block. In this case, the compiler provides us with weak references. Therefore, circular references are not generated.

Since I have been writing blocks like this all the time, when a friend asks me, I will say that it will not be referenced cyclically, because what access method does he encounter, I answered this question. Because of the verbal descriptions, it is really a thousand miles away from the actual response... Haha. In order to verify this, I wrote this article specifically, hoping to help you. Finally, thank you for your time.












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.