8

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
}

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

4

2 回答 2

6

传递块变量可以是 nil,在调用之前检查或在函数开始时添加断言,否则你会崩溃

由于您没有保留 self 并且我们假设您在执行代码时在后台线程上执行了一些长任务,weakSelf 可以为零(希望您使用的是 ARC 和 5.0,因此您有 niled 弱引用)。

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

如果对象指针为 nil,使用 '->' 访问 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 是否为 nil 以防止执行昂贵的任务,如果它没有意义(对象已经被破坏)。但这取决于用例。

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

于 2012-07-04T10:40:22.223 回答
1

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

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

- (void)makeIsFinishedYes
{
    isFinished_ = YES;
}
于 2013-05-07T10:14:18.013 回答