Objective-C - 使用子视图

时间:2011-09-29 15:00:22

标签: objective-c uiview uitableview

我有点困惑。我正在继承UITableViewCell来创建我自己的单元格设计。在-initWithStyle:方法中,我设置了一些UILabel,如下所示:

self.careerTitleLabel = [[UILabel alloc] init];
[self.contentView addSubview:careerTitleLabel];
[self.careerTitleLabel release];

然后定位标签我在-layoutSubviews中这样做:

CGRect careerTitleLabelFrame = CGRectMake(10, 10, 280, 20);

self.careerTitleLabel.frame = careerTitleLabelFrame;

此代码实际上有效。它将我的标签定位在我希望它定位的位置。但我不明白的是 HOW 这是有效的。因为我只是修改了careerTitleLabel ivar的框架,而不是已经作为subView添加到contentView的careerTitleLabel。

我的假设是修改我添加到contentView的标签的框架,我必须使用-viewWithTag:将其拉出来,然后修改该框架。现在我只是在修改班级的伊娃?

P.S与此问题无关的另一个悬念是为什么self.careerTitleLabel在释放后的retainCount为2? D.S

2 个答案:

答案 0 :(得分:3)

addSubview:不会复制您传递的视图,它会保留它。所以当你发布它时,它实际上并没有被释放。由于self.contentView仍在使用它,因此它保持活着状态。这意味着你以后对self.careerTitleLabel的引用仍然可行,但我认为大多数人会认为它是不好的风格,理由是你应该继续拥有对你打算稍后发送的任何对象的引用,而不是从其他地方使用的所有权模式中归咎于知识。

retainCount永远不会完全依赖。它也是不透明的addSubview:将增加保留计数,除了它至少为1.这就是说,最可能的原因,如果你已宣布careerTitleLabel为财产并拥有像这样的一行:

NSLog(@"%d", [self.careerTitleLabel retainCount]);

标准的吸气剂是:

return [[careerTitleLabel retain] autorelease];

因此,getter暂时增加了保留计数,其原因是getter的结果至少应该与autorelease池一样长 - 即使你从中获取它们的对象在那之前被解除分配。

答案 1 :(得分:1)

careerTitleLabel是指向对象的指针。因此,当您执行addSubview: careerTitleLabel时,您调用的代码会保留对careerTitleLabel的引用。

稍后,当您在careerTitleLabel中的layoutSubviews上设置框架时,您正在更新同一个对象。

layoutSubviews绝对是正确的选择。它在开始时自动调用,如果视图边界发生变化则再次调用。例如,如果设备的方向发生变化。

viewWithTag是访问子视图的另一种方式。我个人认为维持ivar更清洁。不要忘记你可以使用IBOutlets使用Interface Builder来连接这些东西。

最后,您确实遇到了内存问题,这解释了保留计数。经常运行Analyze来解决这些问题,并使用Leaks进行配置文件,这是很好的。您甚至可以在构建设置中设置一个标记,以便在每次构建时始终运行Analyze。

无论如何这是问题所在:

self.careerTitleLabel = [[UILabel alloc] init];

如果.h文件中的属性设置为:

@property (nonatomic, retain)
那么你会在这里过度保留。您将保留两次,这将导致内存问题。

Apple指南建议您不要在init方法中调用这些setter。在那个阶段,行为可能是不可预测的,因为您可能正在通过自定义setWhatever方法,而您的对象尚未完成它的初始化。

更安全的是:

    careerTitleLabel = [[UILabel alloc] init];

更好的是,在你的.h文件前缀中,这个成员变量为“m”。那你就有了

    mCareerTitleLabel = [[UILabel alloc] init];

在你的合成中,使用:

    synthesize careerTitleLabel = mCareerTitleLabel;

这意味着从您的代码的外部或内部,您可以访问:

    self.careerTitleLabel

    myObjectName.careerTitleLabel

我希望这有帮助!这要涵盖很多!