堆block & block访问oc变量

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对象释放了。如:










猜你喜欢

转载自blog.csdn.net/zj510/article/details/48245497