为什么 addSubview: 不保留视图? [英] Why is addSubview: not retaining the view?
问题描述
我正在向我的视图中添加两个子视图,它们由属性存储.将子视图添加到我的视图时,子视图似乎在我的 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];
回想一下,horizontalLineView
属性很弱.让我们通过 ARC 生成的额外代码来了解该行中真正发生的事情.首先,您发送 alloc
和 initWithFrame:
方法,获取强引用:
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];
此时,HorizontalLineView
对象的保留计数为 1.接下来,因为您使用点语法设置了 horizontalLineView
属性,编译器生成代码以将 setHorizontalLineView:
方法发送到 self
,传递 temp
作为参数.由于 HorizontalLineView
属性被声明为 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->_horizontalLineView
设置为 temp
,并将 &self->_horizontalLineView
放在对象的弱列表中参考.但它不会增加 HorizontalLineView
对象的保留计数.
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];
这会将 HorizontalLineView
对象的保留计数降低到零,因此它会释放该对象.在释放期间,它会遍历弱引用列表,并将每个弱引用设置为 nil
.所以 self->_horizontalLineView
变成了 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
变量显式,这样你就可以延长它的生命周期,直到你将 HorizontalLineView
对象添加到它的超级视图,这保留它:
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屋!