I want to test the block function and the value for the context. The test code is:
//xxx.h
@interface textObj : NSObject
@property (nonatomic, retain) NSNumber * num;
@end
typedef void (^ returnHandle)(NSNumber * res);
@interface BlockTest : NSObject
- (void) textBlock:(textObj *)num completionHandler:(void (^)(NSNumber * res))handler;
@end
//xxx.m
@implementation textObj
@synthesize num;
@end
@interface BlockTest (){
returnHandle rt;
}
- (void)toggleChromeDisplay;
@end
@implementation BlockTest
- (void) dealloc{
Block_release(rt);
[super dealloc];
}
- (void)toggleChromeDisplay
{
NSNumber *ret = [NSNumber numberWithInt:111];
rt(ret);
}
void (^handle)(NSNumber * res, NSError *error);
- (void) textBlock:(textObj *)g1 completionHandler:(void (^)(NSNumber * res))handler
{
rt = Block_copy(handler);
[self performSelector:@selector(toggleChromeDisplay) withObject:nil afterDelay:0.5];
return;
}
@end
The test sample invoke code is :
//first sample code...
- (void)viewDidLoad
{
[super viewDidLoad];
test = [[BlockTest alloc]init];
textObj * g1;
g1 = [[textObj alloc] init];
[g1 setNum:[NSNumber numberWithInt:10]];
NSLog(@"main 0 g1 num=%@ count=%d", [g1 num], [g1 retainCount]);
[test textBlock:g1 completionHandler:^(NSNumber *res) {
NSLog(@"value=%@", [g1 num]);
[g1 setNum:[NSNumber numberWithInt:20]];
NSLog(@"main 1 g1 num=%@ count=%d", [g1 num], [g1 retainCount]);
} ];
NSLog(@"main 2 g1 num=%@ count=%d", [g1 num], [g1 retainCount]);
[g1 release];
NSLog(@"main 3 g1 num=%@ count=%d", [g1 num], [g1 retainCount]);
}
In the block function, i can change the g1 value. It is OK.
But when I declare the g1 as the public value for the test, it will error in the block function. The g1 can not be access. It output the EXC_BAD_ACCESS(code=2, address=0x26) error.
//second sample code...
@interface UIMainViewController (){
@public
textObj * g1;
}
@end
- (void)viewDidLoad
{
[super viewDidLoad];
test = [[BlockTest alloc]init];
//textObj * g1;
g1 = [[textObj alloc] init];
[g1 setNum:[NSNumber numberWithInt:10]];
NSLog(@"main 0 g1 num=%@ count=%d", [g1 num], [g1 retainCount]);
[test textBlock:g1 completionHandler:^(NSNumber *res) {
NSLog(@"value=%@", [g1 num]);
[g1 setNum:[NSNumber numberWithInt:20]];
NSLog(@"main 1 g1 num=%@ count=%d", [g1 num], [g1 retainCount]);
} ];
NSLog(@"main 2 g1 num=%@ count=%d", [g1 num], [g1 retainCount]);
[g1 release];
NSLog(@"main 3 g1 num=%@ count=%d", [g1 num], [g1 retainCount]);
}
I am confuse the two different sampe code, why the second test code will meet crash?
The primary problem is that, as @H2CO3 points out, you’re releasing
g1before the block is executed. The reason it works in one case and not the other is that blocks retain any local object variables they refer to when copied.In your first example,
g1is a variable local to the method scope, so the block retains it.In your second example,
g1is an ivar (effectivelyself->g1), so the block retainsself. But you releaseg1right after you declare the block, so when the block callsself->g1, it gets an invalid pointer, becauseg1has been deallocated.