2010-01-19 54 views
1

虽然编码总是有与IBOutlets的保留计数相同的问题:来自NIB的对象解除保存后保留计数?何时使用@ property作为IBOutlet?设置时保留还是分配? Mac和iPhone的区别?保留IBOutlets的计数

所以我从Apple的文档中读取The Nib Object Life Cycle。在Mac和iPhone上的一些测试应用程序给了我一些奇怪的结果。不过,我写下了一些规则如何处理这一问题,以保持快乐而编码,但现在想验证与社区,听取您的意见和经验:

  1. 始终为顶级对象创建一个IBOutlet。对于非顶级对象(如果需要)(需要访问)。在Mac
    • 顶级对象:
    • 始终为IBOutlets如下提供一个属性(并释放他们在必要!)
      • @属性(非原子,分配)IBOutlet中SomeObject * someObject ;
      • @synthesize someObject;
      • [self.someObject release];在Mac
    • 非顶级对象(没有发布):
      • @属性(非原子,分配)IBOutlet中NSWindow *窗口;
      • @synthesize someObject;在iPhone上
    • 顶级对象(必须保留):
      • @属性(非原子,保留)IBOutlet中SomeObject * someObject;
      • @synthesize someObject;
      • [self.someObject release];在iPhone上
    • 非顶级对象(应该保留):
      • @属性(非原子,保留)IBOutlet中的UIWindow *窗口;
      • @synthesize window;
      • [self.window release];

旁注:

  • 在Mac和iPhone出口连接与如有二传手做。
  • 顶级对象:“have [...]没有所属对象”
  • 非顶层对象:‘具有父母或所属对象的任何对象,例如嵌套视图层次结构内的意见’

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

我希望你可以批准或纠正

回答

10

始终有你的笔尖文件的所有者是NSWindowController或NSViewController(在Mac OS X)或UIViewController的(在iPhone)的一个子类,并使用@property (retain) IBOutlet其所有网点,做您的控制器子类-dealloc方法中的适当版本。

这种模式将罚款上的Mac OS X iPhone OS,因为NSWindowController和NSViewController Mac OS X上采取顶层对象的隐式拥有权给你(和放弃在自己-dealloc方法) ,并且在加载nib期间iPhone OS不会为您获取顶级对象的任何隐式所有权。

+0

这是一个非常明确的答案,我非常感谢你(尽管我没有足够的声望投票)。这应该在Apple的文档中提及!一个问题:不应该有一个NIBs的文件所有者的类不能成为NSWindowController,NSViewController或UIViewController的子类的情况,对吧? – 2010-01-26 17:24:49

+1

文件的所有者可以是NSObject的子类或任何子类,如果你想要的话。这真的取决于你。然而,使用NSWindowController,NSViewController,UIViewController等开发的现代可可开发工具是围绕让这些控制器管理其笔尖的顶级资源来实现的。 – 2010-01-28 01:41:14

0

我可以写我对iPhone NIB发展的意见:

  • 如果您使用IB,那么请尽可能多地使用IBOutlets(有时,当您构建NIB时,您不知道视图层次结构 - 它可能是动态的),或根本不使用它们 - 否则会出现混乱
  • 只有当你想从视图控制器外部访问的意见(如果它们应该是公共的)
  • AFAIK有没有需要管理IBOutlets

希望它可以帮助记忆

  • 使用属性...

  • +0

    您也可以拥有私有属性(属性未在公共.h标头中定义)。 – 2010-01-20 06:44:46

    +0

    是的,我知道。您也可以在应该私有的成员之前添加“@private” - 这也会将这些属性变为私有。我写了关于IBOutlets的文章。我看到将一个属性添加到IBOutlet的唯一原因是需要将它们公开... – 2010-01-23 21:16:44

    +0

    @Raphael,至于你关于“私人类本地类别扩展”的问题 - 这是一个常规类“.m”文件。这样,没有其他类知道它的存在(因为你导入了“.h”文件)。你可以使用这个解决方法(在我看来这是一个解决方法)来声明私有属性和方法。另外,正如我已经提到的,有一个更好的方法来声明私有财产(而不是方法) - 通过在成员之前(在@interface块内)书写“@private”... – 2010-01-24 11:31:20

    0

    您应遵循标准内存管理指导原则。如果您的插座连接到retain ed属性,则必须在-dealloc消息中释放它。

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

    1

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

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

    Windows有这种选择可以让自己更方便,但是我发现我的设计比较干净(即使是更多的工作),当我关闭它并自己管理它的一生时,就像我拥有的​​任何其他对象一样,或使用窗口控制器。

    如果你认为你被引用的文件相冲突,让我们通过全款:

    对象中最初的1一挡计数创建的笔尖文件由于它重建的对象层次但是,AppKit会自动释放具有父级或拥有对象的任何对象,例如嵌套在视图层次结构内的视图。

    因此杀掉了自己的所有权。笔尖加载器不想拥有你的对象。

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

    换句话说,它把所有权交给你。

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

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

    但是,如果你这样做,即使你释放了它的所有权,对象仍然会保持活动状态。

    我想我会去提出一个关于这个问题的错误。 (编辑:完成。x-radar:// problem/7559755)至少,笔尖加载器不应该在my test app(10.5.8和10.6.1)中保留两个

    +0

    “但是,如果你这样做,即使你释放了它的所有权,该对象仍然会保持活跃状态​​。”不,它不会。如果您有一个IBOutlet保留属性,当视图消失并且您释放IBOutlets时,该对象将被释放。我没有看到你从文档中得到了什么,我从实际经验中知道它是如何工作的(在电话中)。 – 2010-01-20 06:43:43

    +0

    是的,至少在目前的Mac OS X上运行我的测试应用程序(我刚添加的链接)。文件似乎暗示这是故意的,当它说顶级对象“有一个积极的保留数并且没有拥有对象”时,但我觉得它是假的行为,我记得它很久以前就不同了(在老虎之下?),这似乎与我最后一句中的后一段相矛盾,因此我的错误报告是关于它的。 – 2010-01-20 07:51:28

    +0

    当我尝试测试项目时,我没有看到任何错误或虚假信息。在两个类中修复“释放”以调用[super release]之后,assign属性以保留计数1结束(然后您释放!!!),并且retain属性的保留计数为2。 NIB加载器为所有顶级对象(当它被卸载时会被释放)保留,然后代码将它自己的保留添加到顶层对象上(或不如assign属性的情况)。 – 2010-01-20 08:26:11

    0

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

    2)我认为你的iPhone的设置是正确的。你也可以在iPhone上使用一个assign属性,它的功能与你所期望的一样......但是在大量使用后,我更喜欢使用retain属性,所以当我考虑释放对象时我是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; 
    ..... 
    
    +0

    感谢您指出我释放对象的方式。我将在未来考虑这一点。所以释放它(通过财产或不),然后将其设置为零是好的做法? IB是否承认连接IB网点的私人物业?你能解释一下“私人班级 - 本地类别扩展”吗?到目前为止,我从来没有看到带空括号的语法。何时使用? – 2010-01-20 23:17:51

    +0

    我猜你上面的代码不起作用,因为IB只解析IBOutlet标签的.h文件,并且你不能连接这些属性。如我错了请纠正我。 – 2010-01-26 18:03:08

    1

    apple's doc上面提到的:

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

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