3

我对内存管理/保留周期有点困惑。这是一个简单的类:

@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
    }];
}
4

2 回答 2

3

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

于 2013-02-12T08:06:55.477 回答
3

在我看来,编译器只是不想为同一个块多次警告你。我不确定这算不算一个功能,但我看不出还有什么可能发生。

假设我们使用相同的编译器版本(我的是 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

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

于 2013-02-12T08:16:24.250 回答