IBOutlet是否需要成为一个财产?
在大多数例子中,我看到了IBOutlets的以下设置:
(Example A) FooController.h: @interface FooController : UIViewController { UILabel *fooLabel; } @property (nonatomic, retain) IBOutlet UILabel *fooLabel; @end FooController.m: @implementation FooController @synthesize fooLabel; @end
但是,这工作也很好(注意:没有财产,没有综合):
(Example B) FooController.h: @interface FooController : UIViewController { IBOutlet UILabel *fooLabel; } @end FooController.m: @implementation FooController @end
例B中定义IBOutlets有什么缺点吗? 像内存泄漏? 似乎工作正常,我更喜欢不公开的属性,因为它们不被使用,它们只用于控制器的实现。 在没有真正需要的情况下将其定义在三个地方并不会让我感到非常干燥(不要重复自己)。
在Mac OS X上,IBOutlet连接如下:
- 查找名为set <OutletName>的方法: 如果存在,就调用它。
- 如果不存在方法,请查找名为<OutletName>的实例variables,将其设置为不保留 。
在iPhone OS上,IBOutlets连接如下:
- 调用[object setValue:outletValue forKey:@“<OutletName>”]
关键的设置值的行为是做这样的事情:
- 查找名为set <OutletName>的方法: 如果存在,就调用它。
- 如果不存在方法,请查找名为<OutletName>的实例variables,将其设置并保留 。
如果你使用一个属性,你将陷入两个平台上的“ 寻找一个名为set <OutletName>的方法:… ”的情况。 如果你只是使用一个实例variables,那么你将在Mac OS X VS iPhone OS上有不同的保留/释放行为。 使用实例variables没有什么问题,只需要在平台之间切换时处理这种行为差异。
这里有一个关于这个主题的完整文档的链接。 http://developer.apple.com/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html#//apple_ref/doc/uid/10000051i-CH4-SW6
在Mac OS X上,IBOutlets默认不保留。 这与iPhone OS上的行为相反:在iPhone OS上,如果不声明属性,则保留属性,并且必须在dealloc
方法中释放此属性。 另外,64位运行时可以使用属性声明来综合实例variables。 这意味着有一天实例variables(带有IBOutlet
)可以省略。
由于这些原因,它是更均匀和兼容的创build总是一个财产和使用IBOutlet
只在财产。 不幸的是,它也比较冗长。
在你的第一个例子中,你总是必须在dealloc
方法中释放出口。 在第二个例子中,您必须使用iPhone OS才能释放sockets。
最终的结果是完全一样的,但是你必须记住一些事情:
-
当使用实例字段作为出口时,不应该在dealloc中释放它们。
-
使用具有(retain)属性的属性时,必须在dealloc中释放该属性(使用
self.property=nil
或释放后备variables)。 这使得它对于发生的事情更加透明。
其实这一切都归结于同样的旧规则:“ 你将释放你分配/保留的东西 ”。 所以如果你使用实例字段作为出口,你没有分配/保留它,所以你不应该释放它。
这些示例可能使用保留,因为示例代码是以编程方式分配和初始化UILabel,然后将其添加到UIView。 很多例子都是这样,因为学习如何使用Interface Builder通常不是他们的重点。
当开发人员通过将IBOulet拖放到标签或其他视图组件时,在“界面生成器”中分配UILabel(button,视图等)时,将使用第二个示例(无属性和不合成)。 在我看来,前面的拖放操作(标签到视图)也添加了子视图,标签到视图 – 依此类推。 标签由View保留; 一个View由Window保留; 窗口由文件所有者保留。 文件的所有者通常是在main中启动的文档。
你会注意到,当你通过你的程序(通过添加一个awakeFromNib
- (void)awakeFromNib { [fooLabel blahblah]; }
fooLabel已经有一个内存地址。
这是因为标签是从一个文件包(nib文件)初始化使用不是初始化,但initWithCoder。 这实质上是将文件stream反序列化为一个对象 – 然后设置IBOutletvariables。 (我们还在谈论IBOutlet方法)。
另请注意,上述iOS方法使用Key Value方法
call [object setValue:outletValue forKey:@"<OutletName>"]
这是Observer / Observable模式。 该模式要求Observable对象引用Set / Array中的每个Observer。 值的改变将迭代Set / Array并同样更新所有Observers。 该设置将已经保留每个观察员,因此缺乏在iOS保留。
更进一步的是猜测。
看来,当你使用Interface Builder的情况下
@property (nonatomic, retain) IBOutlet UILabel *fooLabel;
应该可能改为
@property (nonatomic, weak) IBOutlet UILabel *fooLabel;
或@property(nonatomic,assign)IBOutlet UILabel * fooLabel;
然后它不需要释放一个dealloc方法。 另外它将满足OSX和iOS的要求。
这是基于逻辑,我可能会错过这里的一些片断。
尽pipe如此,如果在程序的整个生命周期中,这个观点是持久的,那也许并不重要。 而模式对话框中的标签(打开,closures,打开,closures)实际上可能会在每个周期中过度保留和泄漏。 这是因为(再次猜测)每个closures的对话框被序列化成一个文件系统,从而坚持x,y的位置和大小,以及它的子视图等。随后反序列化…在下一个会话打开(相反的说minimiz或隐藏)。