为什么addSubview:不保留视图?

时间:2012-03-17 03:32:24

标签: iphone objective-c ios cocoa-touch uiview

我正在添加两个由属性存储的子视图到我的视图中。将子视图添加到我的视图时,在调用setup方法后,子视图似乎已取消分配。最终结果是视图永远不会显示。现在,如果我将我的属性更改为strong而不是weak,我会保留对视图的引用,现在它们将显示在屏幕上。那么这里发生了什么?为什么addSubview:insertSubview:没有保留子视图?请参阅以下代码:

不过,我正在使用带有ARC的iOS5(因此强弱的东西)

#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;
}

3 个答案:

答案 0 :(得分:21)

以下是您的代码行:

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

回想一下horizontalLineView属性很弱。让我们通过ARC生成的额外代码,了解该行中真正发生的事情。首先,您发送allocinitWithFrame:方法,获得强大的参考资料:

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

此时,HorizontalLineView对象的保留计数为1.接下来,因为您使用了点语法来设置horizontalLineView属性,所以编译器会生成代码以发送{{1}方法setHorizontalLineView:,传递self作为参数。由于temp属性声明为HorizontalLineView,因此setter方法执行此操作:

weak

设置objc_storeWeak(&self->_horizontalLineView, temp); 等于self->_horizontalLineView,并将temp放在对象的弱引用列表中。但它增加&self->_horizontalLineView对象的保留计数。

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

temp

[temp release]; 对象的保留计数降低为零,因此它会释放该对象。在解除分配期间,它会向下遍历弱引用列表,并将每个引用设置为HorizontalLineView。因此nil变为self->_horizontalLineView

解决此问题的方法是使nil变量显式化,以便您可以延长其生命周期,直到将temp对象添加到其超级视图后保留它:

HorizontalLineView

答案 1 :(得分:3)

除非在父母子女保留周期形成的情况下(父母保留对孩子的引用,孩子保留对父母的引用,因此两者都不被dealloc'd),否则不应该使用弱。强与ARC相当于retain(现在在ARC下无效),并且保持一个很好的稳定指针指向对象的时间比弱引用长得多,因此addSubview实际上可以工作,而不是给你一些错误。

  

为什么addSubview:和insertSubview:不保留子视图?

你有没有试过在零对象上调用retain?是的,仍然没有。你的弱引用并没有将UIView对象保持足够长的时间,以便在对象上成功“调用retain”。

答案 2 :(得分:0)

请尝试使用此代码:

    @property (nonatomic, retain)