2

我已经习惯于使用引用和引用以及何时使用它们以及何时不使用它们,我遇到了如下所述的情况(查看有关警告的评论)

@interface MPIViewController ()
@property (weak, nonatomic) UIView *subview;
@property (weak, nonatomic) UILabel *label;
@end

@implementation MPIViewController
// ...
// some code here
// ...  

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.subview = [[UIView alloc] init];   // warning here: assigning retained object to weak property 
    self.label = [[UILabel alloc] init];    // no warnings

    [self.view addSubView: self.subview];
    [self.view addSubView: self.label]; 
}

// ...
// some code here
// ...  
@end

从描述- (void)addSubview:(UIView *)view

该方法建立了对视图的强引用,并将其下一个响应者设置为接收者,即其新的超级视图。

这意味着该对象不会deallocated在方法完成后出现,因为它superview会保留它并持有对它的强引用,因此只要它的父视图存在,这个视图就会一直保存在内存中。我在这里吗?

我也不确定我是否理解在这里正确分配。警告说它会deallocated在分配之后直接进行,但这听起来是错误的,因为这样就不可能将任何变量分配给弱指针,因为它会进入deallocated下一行代码?

对于UILabel相同的分配工作正常,但UIView它没有?编译器是否以某种不同的方式对待 UIView?这真的让我感到困惑,这怎么可能。

只需将 UIView 分配给本地方法变量,然后将其传递给 setter,就可以轻松修复此代码,如下所示:

UIView *tmpView = [[UIView alloc] init];
self.subview = tmpView;

方法中声明的变量是默认的strong,因此具有这样的构造会消除警告,因为编译器认为该变量具有强引用,因此只要方法变量指向它,那么随后分配给的弱引用将被保留。但!这有什么意义,因为 tmpView 只是一个局部方法变量,并且在方法完成后将被转储?

4

2 回答 2

2

对于第一个问题:

让我们仔细看看它:

self.subview = [[UIView alloc] init];

[UIView alloc]返回所有权 +1 的实例。这被分配给一个(不可见的)强引用,它构建self-init. -init通过所有权。(这是不正确的,如果-init返回一个不是原始接收者的实例,但对于您的情况,这已经足够详细了。)所以我们也可以将返回值-init视为所有权转移。

您将此实例分配给一个弱变量。在这一刻,它可以被释放。(阅读:ARC 不承诺立即执行,IIRC。)实例变量可以nil在对象被其父视图持有之前。所以这段代码很危险:

self.subview = [[UIView alloc] init];
// _subview can be nil'ed
[self.view addSubView: self.subview]; // add nil

我不相信这是你的问题,但它可能是一个问题。——再想一想,你的问题。阅读最后的编辑。– 要摆脱它,只需使用强局部变量:

UIView *subview = [[UIView alloc] init]; // defaults to __strong
[self.view addSubView: subview]; // adds an ownership
self.subview = subview;

第二个问题:

我不知道,为什么编译器在第二种情况下没有给你警告。如果您修复第一个案例,会发生什么?

在运行时,两种情况的不同处理是可能的,因为当第一个实例被释放时它是未定义的。也许作为优化的一部分,指针被重用。更详细:

__strong id completlyHiddenCompilerGeneratedVar;
… = [(completlyHiddenCompilerGeneratedVar=[UIView alloc]) init];
… = [(completlyHiddenCompilerGeneratedVar=[UILabel alloc]) init];

当创建第二个实例时,第一个实例将被释放,因为它覆盖了内部强引用。

再次:修复第一个案例并告诉我们,第二个案例会发生什么。

于 2013-10-29T13:58:59.990 回答
0

一个对象至少需要一个指向它的强指针才能保存在内存中。

因此,当您将其分配给弱指针时,该条件未得到满足。strong如果您确实需要访问这些视图,请创建您的属性。

于 2013-10-29T11:50:03.860 回答