为什么不访问self的属性会在self拥有的块中引发编译器警告

时间:2013-02-12 07:52:34

标签: ios objective-c cocoa-touch

我对内存管理/保留周期感到有些困惑。这是一个简单的课程:

@interface Test : NSObject {
    NSObject *objectA;
}
@property (nonatomic, strong) NSObject *objectB;

- (void)methodA;
@end

假设我有一个由Test实例拥有的块。在这个块中,我做了:

    objectA = nil;

我得到一个编译器减弱说它在这个块中捕获自我并且它将导致保留周期。为什么?我在这里看不到自己。

然后,如果我这样做:

self.objectB = nil;

没有警告!如果有的话,我应该在这里发出警告。

如果我这样做:

[self methodA];

我在这里得到一个警告。所以我不确定幕后发生了什么。我希望第一个没有给我一个警告,最后两个给我一个警告(因为我保持一个强烈的指针自我),但它实际上是相反的。

以下是一个例子:

@interface ListVC () {
    NSObject *objectA;
}
@property (nonatomic, strong) NSObject *objectB;
- (void)methodA;
@end

并在viewDidLoad中:

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.tableView addPullToRefreshWithActionHandler:^{
        self.objectB = nil; //no warning here
        objectA = nil; //warning here
        [self methodA]; //warning here (if i place this above previous warning
    }];
}

2 个答案:

答案 0 :(得分:3)

第一个警告是正确的。访问块中的实例变量将隐式保留self。 你没有收到第二个语句警告的事实几乎看起来像编译器错误。

答案 1 :(得分:3)

在我看来,编译器只是不打扰多次警告你同一个Block。我不确定这是一个特色,但我看不出还有什么可以继续。

假设我们使用相同的编译器版本(我的是Apple LLVM 4.2),试试这个:

@interface Jubilee : NSObject

@property (copy, nonatomic) NSData * d;

@end

@implementation Jubilee
{
    NSString * s;
    dispatch_block_t block;
}

@synthesize d;

- (void)erase
{
    block = ^{
        s = @"Agamemnon";
    };

    block = ^{
        self.d = [NSData data];
    };

    block = ^{
        [self prevaricate];
    };

}

- (void)assemble
{
    block = ^{
        s = @"Agamemnon";
        self.d = [NSData data];
        [self prevaricate];
    };
}

- (void)prevaricate
{
}

@end

我在erase内的每个区块都收到警告,但仅针对assemble中区块的第一行。任何这些线路上的警告都是正确的。当您对ivar进行裸引用时,它隐式self->ivar;,并且Block将保留self而不是ivar中的对象。