Iphone IBOutlet是否需要是一个属性&;合成的?

Iphone IBOutlet是否需要是一个属性&;合成的?,iphone,interface-builder,Iphone,Interface Builder,在大多数示例中,我看到以下IBOutlets设置: (Example A) FooController.h: @interface FooController : UIViewController { UILabel *fooLabel; } @property (nonatomic, retain) IBOutlet UILabel *fooLabel; @end FooController.m: @implementation FooController @synt

在大多数示例中,我看到以下IBOutlets设置:



(Example A)

FooController.h:

@interface FooController : UIViewController {
    UILabel *fooLabel;
}

@property (nonatomic, retain) IBOutlet UILabel *fooLabel;

@end

FooController.m:

@implementation FooController

@synthesize fooLabel;

@end

但这也很好(注意:没有属性也没有合成):


如例B所示定义IBOutlets有什么缺点吗?比如内存泄漏?似乎工作得很好,我不想将IBOutlets公开为公共属性,因为它们不是这样使用的,它们只在控制器实现中使用。在没有实际需要的情况下,在三个地方定义它不会让我觉得很枯燥(不要重复你自己)。

最终结果完全相同,但你必须记住以下几点:

  • 将实例字段用作出口时,不应在dealoc中释放它们

  • 使用具有(retain)属性的属性时,必须在dealloc中释放属性(使用
    self.property=nil
    或通过释放支持变量)。这使得事情变得更加透明


实际上,这一切都归结为同一条老规则:“你应该释放你分配/保留的东西”。因此,如果您使用实例字段作为出口,您没有分配/保留它,因此不应该释放它。

在Mac OS X上,IBOutlets的连接方式如下:

  • 查找名为set的方法:。如果它存在,就叫它
  • 如果不存在方法,请查找名为的实例变量,将其设置为,但不保留
  • 在iPhone操作系统上,iBouts的连接方式如下:

  • 调用[object setValue:outletValue forKey:@”“]
  • 键的set value的行为如下所示:

  • 查找名为set的方法:。如果它存在,就叫它
  • 如果不存在方法,请查找名为的实例变量,设置它并保留它
  • 如果使用属性,则在两种平台上都会出现“查找名为set:…”的方法”的情况。如果只使用实例变量,那么Mac OS X和iPhone OS上的保留/释放行为将不同。使用实例变量没有什么错,只需要在平台之间切换时处理这种行为差异

    这里有一个关于这个主题的完整文档的链接。

    在Mac OS X上,默认情况下不会保留IBoutlet。这与iPhone操作系统上的行为相反:在iPhone操作系统上,如果不声明属性,它将被保留,并且必须在
    dealoc
    方法中释放此属性。此外,64位运行时可以使用属性声明合成实例变量。这意味着有一天实例变量(带有
    IBOutlet
    )可能会被省略

    由于这些原因,始终创建一个属性并仅在属性中使用
    IBOutlet
    更为一致和兼容。不幸的是,它也更加冗长


    在第一个示例中,您必须始终使用
    dealloc
    方法释放插座。在第二个示例中,您必须仅使用iPhone操作系统释放插座。

    这些示例可能使用retain,因为示例代码以编程方式分配和初始化UILabel,然后将其添加到UIView。很多例子都是这样,因为学习如何使用Interface Builder通常不是他们的重点

    第二个例子(无属性和无合成)是在开发人员在界面生成器中“分配”UILabel(按钮、视图等)时使用的,方法是将IBOulet拖到标签或其他视图组件上。在我看来,前面的拖放操作(标签放到视图上)也会添加子视图、标签到视图,依此类推。标签由视图保留;窗口保留一个视图;窗口由文件的所有者保留。文件的所有者通常是在main中启动的文档

    您将注意到,当您单步执行程序时(通过添加awakeFromNib)

    - (void)awakeFromNib
    {
        [fooLabel blahblah];
    }
    
    那个傻瓜已经有一个内存地址了

    这是因为标签是从文件包(nib文件)初始化的,使用的不是init而是initWithCoder。它本质上是将文件流反序列化为一个对象,然后设置IBOutlet变量(我们仍然在讨论IBOutlet方法)

    还要注意,前面提到的iOS方法使用Key-Value方法

      call [object setValue:outletValue forKey:@"<OutletName>"]
    
    可能应该改为

    @property (nonatomic, weak) IBOutlet UILabel *fooLabel;
    
    或 @属性(非原子,赋值)IBUILabel*傻瓜标签

    然后它就不需要以dealloc的方式发布,而且它还可以满足OSX和iOS的要求

    这是基于逻辑,我可能会遗漏一些东西


    尽管如此,视图是否在程序的整个生命周期内保持不变可能并不重要。然而,模式对话框中的标签(打开、关闭、打开、关闭)实际上可能会在每个周期内过度保留和泄漏。这是因为(再次推测)每个关闭的对话框都被序列化到文件系统中,从而保持x、y位置和大小以及其子视图等,然后在下一个打开的会话中反序列化(而不是说最小化或隐藏)。

    此建议适用于Mac OS x,但不适用于iPhone OS。请参阅下面的答案。调用“self.property=nil”在dealloc方法中,这不是一个很好的实践。您不应该从init或dealloc调用方法,如果您是子类化的,那么您的子类可能不希望这些setter在解除锁定之后或初始化之前被调用。这是释放使用实例变量合成的自动保留属性的唯一方法(无任何支持字段的明确声明)。您没有选择,不管是好的做法还是不好的做法。如果您没有使用垃圾收集,请声明一个备份实例变量。这就是要点:使用实例变量合成时没有备份实例变量。因此,如果您选择使用自动实例变量合成,则释放它的唯一方法是通过设置把房子归零。嗨,乔恩,谢谢你详细的回答
     @property (nonatomic, retain) IBOutlet UILabel *fooLabel;
    
    @property (nonatomic, weak) IBOutlet UILabel *fooLabel;