1

虽然编码总是出现关于 IBOutlets 保留计数的相同问题:从 NIB 取消归档对象后保留计数?何时将@property 用于 IBOutlet?设置时保留还是分配?Mac 和 iPhone 的区别?

所以我从 Apple 的文档中阅读了 The Nib Object Life Cycle 。Mac 和 iPhone 上的一些测试应用程序给了我一些奇怪的结果。尽管如此,我还是写了一些规则来处理这个问题,以便在编码时保持快乐,但现在想与社区进行验证并听取您的意见和经验:

  1. 始终为顶级对象创建 IBOutlet。必要时用于非顶级对象(需要访问)。
  2. 始终为 IBOutlets 提供如下属性(并在必要时释放它们!):
    • Mac 上的顶级对象:
      • @property (nonatomic, assign ) IBOutlet SomeObject *someObject;
      • @synthesize someObject;
      • [self.someObject释放];
    • Mac 上的非顶级对象(无版本):
      • @property (nonatomic, assign ) IBOutlet NSWindow *window;
      • @synthesize someObject;
    • iPhone 上的顶级对象(必须保留):
      • @property(非原子,保留) IBOutlet SomeObject *someObject;
      • @synthesize someObject;
      • [self.someObject释放];
    • iPhone 上的非顶级对象(应保留):
      • @property (nonatomic, 保留) IBOutlet UIWindow *window;
      • @synthesize 窗口;
      • [self.window释放];

旁注:

  • 在 Mac 和 iPhone 上,如果可用,则使用 setter 进行插座连接。
  • 顶级对象:“没有 [...] 拥有对象”
  • 非顶级对象:“任何具有父对象或拥有对象的对象,例如嵌套在视图层次结构中的视图。”

所以问题是:这是正确和好的做法吗?

我希望你能批准或更正它。

4

6 回答 6

10

始终让您的 nib 的文件所有者成为 NSWindowController 或 NSViewController(在 Mac OS X 上)或 UIViewController(在 iPhone 上)的子类,并@property (retain) IBOutlet用于其所有出口,在您的控制器子类-dealloc方法中进行适当的发布。

这种模式在Mac OS X和iPhone OS 上可以正常工作,因为 Mac OS X 上的 NSWindowController 和 NSViewController 为您获取顶级对象的隐式所有权(并在他们自己的方法中放弃),而 iPhone OS 不接受任何在 nib 加载期间为您隐式拥有顶级对象。-dealloc

于 2010-01-21T04:10:04.177 回答
1

顶级对象:“没有 [...] 拥有对象”

尼克斯。顶级对象由文件的所有者拥有,文件的所有者是文件的所有者,因为它拥有文件中的所有顶级对象。

Windows 可以选择释放自己作为一种便利,但是当我关闭它并自己管理它的生命周期时,我发现我的设计更简洁(即使它是一个多一点的工作),就像我拥有的​​任何其他对象一样,或者使用一个窗口控制器。

如果您认为这与您引用的文档有冲突,让我们看一下整个段落:

nib 文件中的对象最初创建时保留计数为 1。但是,当它重建对象层次结构时,AppKit 会自动释放任何具有父对象或拥有对象的对象,例如嵌套在视图层次结构中的视图。

从而扼杀了自己的所有权。nib 加载器不想拥有您的对象。

到 nib 加载代码完成时,只有 nib 文件中的顶级对象具有正保留计数并且没有拥有对象。您的代码负责释放这些顶级对象。

换句话说,它将所有权移交给您。

奇怪的是,如果您的属性具有保留语义,您实际上会泄漏该对象。文档说你应该保留它:

对于 Mac OS X 和 UIKit,管理 nib 文件中的顶级对象的推荐方法是在 File's Owner 对象中为它们创建 outlet,然后定义 setter 方法以根据需要保留和释放这些对象。

但是,如果您这样做,即使您释放了对象的所有权,该对象仍将保持活动状态。

我想我会去提交一个关于这个的错误。(编辑:完成。x-radar://problem/7559755)至少,笔尖加载器不应该交出两个保留,这在我的测试应用程序中(在 10.5.8 和 10.6.1 上)。

于 2010-01-20T06:05:00.903 回答
1

从上面提到的苹果文档

对于 Mac OS X 和 UIKit,管理 nib 文件中的顶级对象的推荐方法是在 File's Owner 对象中为它们创建 outlet,然后定义 setter 方法以根据需要保留和释放这些对象。Setter 方法为您提供了一个适当的位置来包含您的内存管理代码,即使在您的应用程序使用垃圾收集的情况下也是如此。实现 setter 方法的一种简单方法是创建声明的属性(使用 @property 语法)并让编译器为您创建它们。有关如何定义属性的更多信息,请参阅 Objective-C 编程语言。

否则使用@property(nonatomic, retain) IBOutlet * outletName;

于 2010-06-29T23:36:41.000 回答
0

我可以写下我对 iPhone NIB 开发的看法:

  • 如果您使用 IB,则使用尽可能多的 IBOutlets(有时您在构建 NIB 时不知道视图层次结构 - 它可能是动态的)或根本不使用它们 - 否则会一团糟
  • 仅当您想从视图控制器外部访问视图时才使用属性(如果它们应该是公共的)
  • AFAIK 无需为 IBOutlets 管理内存

希望能帮助到你...

于 2010-01-20T00:29:33.460 回答
0

1)一般来说,为什么你会有一个没有 IBOutlet 的顶级对象来指向它?这一要求似乎从来没有非常严格。

2)我认为您的设置适合​​ iPhone。您也可以在 iPhone 上使用 assign 属性,这符合您的预期......但一般来说,经过大量使用后,我更喜欢使用保留属性,所以当我考虑释放对象时,我 100% 清楚(尤其是用 viewDidUnload 方法来实现)。

另外,作为旁注,调用 [self.property release] 不是一种好的形式。这会使引用保持完整但可能无效,如果其他东西也释放了对象......要么说 self.property = nil,要么(更好)将底层类变量直接设置为 nil,而不使用 dealloc 语句中的属性(以避免任何dealloc 中可能的副作用)。

正如我在回复另一张海报时提到的,您可以通过使用在私有类本地类别扩展中声明的 IBOutlet 属性来保持清洁,因此它们不是公共属性。看起来像:

// in .m file
@interface MyClass ()
@property (nonatomic, retain) IBOutlet UIView *myPrivateView;
@end

@implementation MyClass
@synthesize myPrivateView;
.....
于 2010-01-20T06:55:40.890 回答
0

您应该遵循标准的内存管理指南。如果您的插座连接到retained 属性,那么您必须在-dealloc消息中释放它。

是的,您通常需要自己保留任何其他对象未保留的任何顶级对象。

于 2010-01-20T00:33:24.263 回答