简体   繁体   English

在ARC中,dealloc方法调用包含对self的弱引用的method / block,从而导致weakSelf = nil

[英]In ARC, dealloc method calls method/block that contains weak reference to self result in weakSelf = nil

As the title states, in ARC mode, when I define a block using self reference (weak to avoid reference cycle): 如标题所述,在ARC模式下,当我使用自引用定义一个块时(避免引用周期较弱):

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

In dealloc I call the block: 在dealloc中,我调用该块:

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

Then I found isNil = YES. 然后我发现isNil = YES。

When I want blocks in dealloc to do something with self, this seems to be a problem. 当我希望dealloc中的块对self做某事时,这似乎是一个问题。

This also happen in callback functions, which I will not give an example here. 回调函数中也会发生这种情况,在此不再赘述。

My solution is using __unsafe_unretained instead of __weak. 我的解决方案是使用__unsafe_unretained而不是__weak。

But this looks ugly. 但这看起来很丑。

Is there better ways to avoid nil weak self in dealloc? 是否有更好的方法来避免在dealloc中出现零自我?

Updated Question: Why weakSelf is niled even when self is not? 更新的问题:为什么即使弱势self weakSelf ,弱势self也会被否定? Is it the reason of dealloc ? dealloc的原因吗?


To make it clear, I paste the test code below: 为了清楚起见,我在下面粘贴了测试代码:

#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;
}

You do not call the block. 您不调用该块。 That would be: 那将是:

BOOL isNil = self.someBlock();

The below works, and in my opinion is cleaner as no reference to self is then held. 下面的作品,我认为更干净,因为那时没有提及self Also there is no real need for the return BOOL of the block now, but I've left this in... 另外,现在并不需要块的返回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;
}

Output : 输出

num = 1
block returned YES
num = 2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM