我已经习惯了使用弱引用和强引用,何时使用它们,何时不使用它们,我遇到了如下所述的情况(检查有关警告的评论)
@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 只是一个局部方法变量,并且在方法完成后将被转储?
对于第一个问题:
让我们仔细看看它:
self.subview = [[UIView alloc] init];
[UIView alloc]
返回所有权为 +1 的实例。这被分配给一个(不可见的)强引用,它构建了-init
的self
。 -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];
创建第二个实例时,第一个实例将被解除分配,因为它会覆盖内部强引用。
再次:修复第一个案例并告诉我们,第二个案例会发生什么。
一个对象至少需要一个指向它的强指针才能保存在内存中。
因此,当您将其分配给弱指针时,该条件不满足。如果您确实需要访问这些视图,请使您的属性strong
。