阅读772 返回首页    go 阿里云 go 技术社区[云栖]


block循环引用解决


block循环引用解决

实验代码


@interface ViewController ()
@property (nonatomic, strong) TestNetworkBlock *testNetwork;
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    self.testNetwork = [[TestNetworkBlock alloc] init];
    
    [self.testNetwork ceshi];
    [self.testNetwork release], self.testNetwork = nil;
}
@end

@interface TestNetworkBlock ()
{
    countBlock _countBlock;
}

@property (nonatomic, strong) NSString *strTest;


@end


@implementation TestNetworkBlock


- (id) init
{
    self = [super init];
    if (self)
    {
        self.strTest = @"我的测试";
        __weak TestNetworkBlock *weakSelf = self;
        _countBlock = ^(int i){
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
                sleep(5);
                NSString *string = [weakSelf zhixing:i];
                NSLog(@"string=====%@", string);
            });
        };
    }
    return self;
}

- (NSString *) zhixing:(int) i
{
    NSString *string = [NSString stringWithFormat:@"%@%d", self.strTest, i];
    
    return string;
}

- (void) ceshi
{
    _countBlock(5);
}

- (void) dealloc
{  
    NSLog(@"======dealloc");
}
@end

问题剖析:

多线程调用,block外面声明了weakSelf,则block内部对self的引用为指针引用,当外部[self.testNetwork release], self.testNetwork = nil;时,weakSelf为nil,所以导致运行失败。

第二种:block改为self引用


_countBlock = ^(int i){
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
                sleep(5);
                NSString *string = [self zhixing:i];
                NSLog(@"string=====%@", string);
            });
        };

问题剖析

_countBlock为self对象,self强引用了_countBlock,同时_countBlock又怕里面self释放,所以block体里面会强引用self。导致循环引用,内存一直不会被释放,dealloc也不会被调用。

正确做法:block内部加入bSelf强引用指针


 __weak TestNetworkBlock *weakSelf = self;
_countBlock = ^(int i){
            TestNetworkBlock *bSelf = weakSelf;
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
                sleep(5);
                NSString *string = [bSelf zhixing:i];
                NSLog(@"string=====%@", string);
            });
        };

问题剖析

在 block 之前定义对 self 的一个弱引用 wSelf,因为是弱引用,所以当 self 被释放时 wSelf 会变为nil;
在block体内部声明一个强引用对象bself指向该wSelf。bSelf只会在block内部执行完毕才会消亡,这样就保证了self对象被外部其他线程释放掉的情况。又避免了循环引用,因为在block执行完,会释放掉bSelf。

最后更新:2017-08-13 22:34:03

  上一篇:go  perl信号量实现进程间通信
  下一篇:go  6个大数据处理分析的最好工具