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

man*_*mal 7 objective-c objective-c-blocks ivar automatic-ref-counting declared-property

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

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

@interface TMSyncBase : NSObject {
     BOOL isFinished_;
}

@property (nonatomic, readonly) BOOL isFinished;
Run Code Online (Sandbox Code Playgroud)

我想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
}
Run Code Online (Sandbox Code Playgroud)

我不确定这是正确的做法.这段代码会泄漏,破坏,还是没问题?也许有一种我更容易被忽视的方式?

Krz*_*cki 6

传递块变量可以是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);
};
Run Code Online (Sandbox Code Playgroud)

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

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