【问题标题】:In ARC, dealloc method calls method/block that contains weak reference to self result in weakSelf = nil在 ARC 中,dealloc 方法调用包含对 self 的弱引用的方法/块导致 weakSelf = nil
【发布时间】:2014-12-09 12:48:00
【问题描述】:

如标题所述,在 ARC 模式下,当我使用自引用定义块时(弱以避免引用循环):

...
id __weak weakSelf = self;
self.someBlock = ^(){
    if (weakSelf != nil){
        (do something with weakSelf...)
        return NO;
    }
    return YES;
};
...

在 dealloc 中我调用了块:

- (void)dealloc {
    ...
    BOOL isNil = self.someBlock();
    ...
}

然后我发现isNil = YES。

当我想让 dealloc 中的块对 self 做某事时,这似乎是个问题。

回调函数中也会出现这种情况,这里我就不举例了。

我的解决方案是使用 __unsafe_unretained 而不是 __weak。

但这看起来很难看。

有没有更好的方法来避免在 dealloc 中出现 nil weak self ?

更新的问题:为什么weakSelf 是无效的,即使self 不是?是dealloc的原因吗?


为了清楚起见,我把测试代码贴在下面:

#import <Foundation/Foundation.h>

@interface blockWeak : NSObject

@property (nonatomic, strong) BOOL (^someBlock)();
@property (nonatomic) int num;

- (void)makeBlock;

@end

@implementation blockWeak

- (void)makeBlock
{
    typeof(self) __weak weakSelf = self;
    self.someBlock = ^(){
        typeof(self) strongSelf = weakSelf;
        strongSelf.num = 2;
        return weakSelf == nil?YES:NO;
    };
}

- (void)dealloc
{
    BOOL isNil = self.someBlock();
    if (isNil) {
        NSLog(@"weakSelf is nil.");
    }
}

@end

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        blockWeak *bw = [[blockWeak alloc] init];
        bw.num = 1;
        [bw makeBlock];
    }
    return 0;
}

【问题讨论】:

  • 除了答案中提到的明显错误之外,您的用例是什么?检查weakSelf 是否已经在dealloc 中被取消似乎不是您应该做的事情。
  • 真正的用例是,我需要块做一些清理工作,而不是在 dealloc 中释放内存,这可能会使用类的属性/ivars,甚至是 self。我稍微修改一下问题以使其更清楚。
  • 你可以在 dealloc 中调用任何东西,甚至使用 self。
  • 我试过了。使用 self 是可以的。我将块上的代码复制到 dealloc 并且它可以工作。但是,当您在 dealloc 中使用包含指向 self 的弱指针的块/函数时,它不起作用,因为当程序进入块/函数内部时,“weakSelf”变为 nil。这就是我感到困惑的原因。

标签: ios objective-c automatic-ref-counting


【解决方案1】:

下面的作品,在我看来更干净,因为没有引用self。 现在也没有真正需要返回块的BOOL,但我已经把它留在了......

#import <Foundation/Foundation.h>

@interface blockWeak : NSObject

@property (nonatomic, copy) BOOL (^someBlock)(blockWeak *);
@property (nonatomic) int num;

- (void)makeBlock;

@end

@implementation blockWeak

- (void)makeBlock
{
    self.someBlock = ^BOOL(blockWeak *object){
        object.num = 2;
        return object == nil?YES:NO;
    };
}

- (void)dealloc
{
    NSLog(@"num = %d", _num);
    BOOL isNil = _someBlock(self);
    if (isNil) {
        NSLog(@"block returned NO");
    } else {
        NSLog(@"block returned YES");
    }
    NSLog(@"num = %d", _num);
}

@end

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        blockWeak *bw = [[blockWeak alloc] init];
        bw.num = 1;
        [bw makeBlock];
    }
    return 0;
}

输出

num = 1
block returned YES
num = 2

【讨论】:

  • 使用self作为block的参数是推迟self的引用的好方法。但我仍然想知道为什么weakSelfdealloc 忽略了。
  • 这很有帮助。谢谢!
【解决方案2】:

您不调用该块。那将是:

BOOL isNil = self.someBlock();

【讨论】:

  • 抱歉打错了。忘记那个
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-23
  • 2019-11-29
  • 1970-01-01
  • 1970-01-01
  • 2013-10-19
  • 1970-01-01
相关资源
最近更新 更多