为什么一个弱引用被释放而另一个没有?



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

@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 的实例。这被分配给一个(不可见的)强引用,它构建了-initself-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

相关内容

  • 没有找到相关文章

最新更新