为什么 addSubview: 不保留视图? [英] Why is addSubview: not retaining the view?

查看:16
本文介绍了为什么 addSubview: 不保留视图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在向我的视图中添加两个子视图,它们由属性存储.将子视图添加到我的视图时,子视图似乎在我的 setup 方法被调用后被释放.最终结果是视图永远不会显示.现在,如果我将我的属性更改为 strong 而不是 weak 我保留对视图的引用,它们现在显示在屏幕上.那么这里发生了什么?为什么 addSubview:insertSubview: 不保留子视图?看下面的代码:

I'm adding two subviews, which are stored by properties, to my view. When adding the subviews to my view the subViews are seemingly deallocated after my setup method is called. The end result is that the views never get displayed. Now, if I change my properties to strong as opposed to weak I retain a reference to the views and they now show on screen. So what's going on here? Why is the addSubview: and insertSubview: not retaining the subviews? See the code below:

顺便说一句,我正在使用带有 ARC 的 iOS5(因此有强有弱的东西)

btw, I'm using iOS5 with ARC (hence the strong and weak stuff)

#import "NoteView.h"
@interface NoteView() <UITextViewDelegate>
@property (weak, nonatomic) HorizontalLineView *horizontalLineView;  // custom subclass of UIView that all it does is draw horizontal lines
@property (weak, nonatomic) UITextView *textView;
@end

@implementation NoteView
@synthesize horizontalLineView = _horizontalLineView;
@synthesize textView = _textView;

#define LEFT_MARGIN 20
- (void)setup
{
    // Create the subviews and set the frames
    self.horizontalLineView = [[HorizontalLineView alloc] initWithFrame:self.frame];
    CGRect textViewFrame = CGRectMake(LEFT_MARGIN, 0, self.frame.size.width, self.frame.size.height);
    self.textView = [[UITextView alloc] initWithFrame:textViewFrame];


    // some addition setup stuff that I didn't include in this question...

    // Finally, add the subviews to the view
    [self addSubview:self.textView];
    [self insertSubview:self.horizontalLineView atIndex:0];
}

- (void)awakeFromNib
{
    [super awakeFromNib];

    [self setup];
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        [self setup];
    }
    return self;
}

推荐答案

这是你的一行代码:

self.horizontalLineView = [[HorizontalLineView alloc] initWithFrame:self.frame];

回想一下,horizo​​ntalLineView 属性很弱.让我们通过 ARC 生成的额外代码来了解该行中真正发生的事情.首先,您发送 allocinitWithFrame: 方法,获取强引用:

Recall that the horizontalLineView property is weak. Let's walk through what really happens in that line, with the extra code that ARC generates. First, you send the alloc and initWithFrame: methods, getting back a strong reference:

id temp = [[HorizontalLineView alloc] initWithFrame:self.frame];

此时,Horizo​​ntalLineView 对象的保留计数为 1.接下来,因为您使用点语法设置了 horizo​​ntalLineView 属性,编译器生成代码以将 setHorizo​​ntalLineView: 方法发送到 self,传递 temp 作为参数.由于 Horizo​​ntalLineView 属性被声明为 weak,setter 方法会这样做:

At this point, the HorizontalLineView object has a retain count of 1. Next, because you used dot-syntax to set the horizontalLineView property, the compiler generates code to send the setHorizontalLineView: method to self, passing temp as the parameter. Since the HorizontalLineView property is declared weak, the setter method does this:

objc_storeWeak(&self->_horizontalLineView, temp);

这将 self->_horizo​​ntalLineView 设置为 temp,并将 &self->_horizo​​ntalLineView 放在对象的弱列表中参考.但它不会增加 Horizo​​ntalLineView 对象的保留计数.

That sets self->_horizontalLineView equal to temp, and puts &self->_horizontalLineView on the object's list of weak references. But it does not increment the retain count of the HorizontalLineView object.

最后,因为不再需要temp变量,编译器生成:

Finally, because the temp variable is no longer needed, the compiler generates this:

[temp release];

这会将 Horizo​​ntalLineView 对象的保留计数降低到零,因此它会释放该对象.在释放期间,它会遍历弱引用列表,并将每个弱引用设置为 nil.所以 self->_horizo​​ntalLineView 变成了 nil.

That lowers the HorizontalLineView object's retain count to zero, so it deallocates the object. During deallocation, it walks down the list of weak references, and sets each one to nil. So self->_horizontalLineView becomes nil.

解决这个问题的方法是让 temp 变量显式,这样你就可以延长它的生命周期,直到你将 Horizo​​ntalLineView 对象添加到它的超级视图,这保留它:

The way to fix this is to make the temp variable explicit, so that you can extend its lifetime until after you have added the HorizontalLineView object to its superview, which retains it:

HorizontalLineView *hlv = [[HorizontalLineView alloc] initWithFrame:self.frame];
self.horizontalLineView = hlv;
// ...
[self insertSubview:hlv atIndex:0];

这篇关于为什么 addSubview: 不保留视图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆