我的界面文件中有一个只读属性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
}
我不确定这是正确的做法。这段代码会泄漏,破坏,还是没问题?也许我忽略了一种更简单的方法?
答案 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;
}