block有三种:global,stack和heap。
通常默认情况下都是stack或者global的,而heap block呢?
另外一个问题如果block里面引用了oc变量,那么就要小心了。如:
#import <Foundation/Foundation.h>
@interface Car : NSObject
@property(nonatomic, readwrite, retain) NSString* name;
@end
@implementation Car
-(id) retain
{
return [super retain];
}
- (oneway void) release
{
[super release];
}
- (void) dealloc
{
self.name = @"";
[super dealloc];
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
Car* car = [[Car alloc] init];
car.name = @"BMW";
void (^Block1)() = ^{
NSLog(@"Block1, instance: %@, name: %@", car, car.name);
};
NSLog(@"block 1: %@", Block1);
Block1();
[car release];
Block1();
}
return 0;
}
在第二次调用block的时候,car对象已经被释放了。那么就会导致不可预测的问题。像这个问题,就需要控制car对象和block的生命周期了。
堆block
先来看看怎么创建堆block。通过Block_copy可以从一个stack block拷贝一个新的block出来,而这个block就是在堆上的。看:
从打印的log就可以看到第二个block是__NSMallocBlock,这就是堆上的一个block。用完需要调用Block_Release来释放这个堆block。
堆block访问oc变量
我们在对象的retain方法那里下个断点,可以看到:
扫描二维码关注公众号,回复:
4573562 查看本文章
当调用Block_copy的时候,car对象的retain会被调用一次,也就是说car对象的引用计数+1了。这样,只要堆block还在,那么car对象就永远不会被释放,直到调用Block_release()方法。这就好像堆block拥有了car对象一样。像这种代码就没问题了,只要保证Block_release()之后不再调用block就行了。
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
Car* car = [[Car alloc] init];
car.name = @"BMW";
void (^Block1)() = ^{
NSLog(@"Block1, instance: %@, name: %@", car, car.name);
};
NSLog(@"block 1: %@", Block1);
Block1();
void (^Block2)() = Block_copy(Block1);
[car release];
NSLog(@"block 2: %@", Block2);
Block2();
Block2();
Block_release(Block2);
}
return 0;
}
所以, 如果说block需要使用外面的oc对象的话,最好使用堆block。
当调用Block_release的时候,car对象的release会被调用,上面的例子里,Block_release调用完后,car引用计数就是0了,dealloc也会被调,也就是car对象释放了。如: