通过弱指针分配到块中的ivar

时间:2012-07-04 10:23:05

标签: objective-c automatic-ref-counting objective-c-blocks ivar declared-property

我的界面文件中有一个只读属性isFinished

typedef void (^MyFinishedBlock)(BOOL success, NSError *e);

@interface TMSyncBase : NSObject {
     BOOL isFinished_;
}

@property (nonatomic, readonly) BOOL isFinished;

我希望稍后在某个块中将其设置为YES,而不会创建self的保留周期:

- (void)doSomethingWithFinishedBlock:(MyFinishedBlock)theFinishedBlock {
    __weak MyClass *weakSelf = self;
    MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) {
        [weakSelf willChangeValueForKey:@"isFinished"];
        weakSelf -> isFinished_ = YES;
        [weakSelf didChangeValueForKey:@"isFinished"];
        theFinishedBlock(success, e);
    };

    self.finishedBlock = finishedBlockWrapper; // finishedBlock is a class ext. property
}

我不确定这是正确的做法。这段代码会泄漏,破坏,还是没问题?也许我忽略了一种更简单的方法?

2 个答案:

答案 0 :(得分:5)

传递块变量可以是nil,在调用之前检查或在函数启动时添加断言或者你将崩溃

由于你没有保留自我,我们假设你在代码执行时执行了一些长任务在执行代码时,weakSelf可能是nil(希望你使用的是ARC和5.0,所以你已经得到了弱引用)。

如果你没有真正的弱引用(< 5.0,没有ARC,编译器仍会接受__weak但是没关系)这会导致崩溃。

使用' - >'访问ivar如果对象指针为零,将导致崩溃,因此您需要确保它不会发生。

即使你像dasblinkenlight写的那样执行代码,如果此时weakSelf将为nil,它会崩溃,假设您在后台线程上调度块然后在块执行之前释放对象,这使得weakSelf nil因此访问它使用' - >'会导致崩溃。在这种情况下,我会修改代码如下:

__weak MyClass *weakSelf = self;
MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) {
    MyClass *strongSelf = weakSelf;
    //! whatever task you want executed
    strongSelf.isFinished = YES;
    theFinishedBlock(success, e);
};

此外,您可以测试weakSelf是否为零以防止执行中的昂贵任务(如果它没有意义)(对象已被破坏)。但这取决于用例。

但是在使用块编程时还需要考虑其他情况,例如: 您可以拥有一个作业对象实例,其唯一的作用是在后台执行某些任务,在这种情况下,此代码可能会失败,因为您将创建新任务并且可以在块在后台线程上执行之前释放它,在这种情况下您应该保留自己并且不保留对象中的块(这将阻止保留周期)。

答案 1 :(得分:0)

一个小小的解决方法是创建一个方法,让编译器为您处理它。工作正常,但我不确定这是不是正确的方法。有人可以判断它是否正确吗?

__weak MyClass *weakSelf = self;
MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) {
    [weakSelf makeIsFinishedYes];
};

- (void)makeIsFinishedYes
{
    isFinished_ = YES;
}