【问题标题】:Is it necessory to define property for an IBOutlet field?是否有必要为 IBOutlet 字段定义属性?
【发布时间】:2010-06-18 21:11:24
【问题描述】:

我见过很多 iPhone 示例使用 IBOutlet 作为与 Interface Builder 中的 UI 控件链接的字段,并且该字段也被定义为接口类中的属性。例如,以下代码与 Apple 示例代码类似:

// in .h file
@interface MyViewController : UIViewController {
  IBOutlet UILabel* _firstName;
  IBOutlet UILabel* _lastName;
  ...
}

@property (nonatomic, retain) UILabel* firstName;
@property (nonatomic, retain) UILabel* lastName;
...
@end

// in .m file
@implementation MyViewController {
@synthetic firstName = _firstName;
@synthetic lastName = _lastName;
...
@end

我尝试将 Interface Builder 中的标签链接到我的控制器类 IBOutlets,我可以看到 _firstName 和 _lastName。因为链接是直接从 Interface Builder 到我的接口类成员(如果我放置 @private 指令,甚至是私有的)。我需要为这些字段定义属性吗?

实际上,我尝试删除这些属性,看来我的代码工作正常。通过定义属性,我的类将它们公开。我没有任何用途或理由将它们作为我的代码内部或外部的属性。我的问题是,如果这种做法,将字段定义为属性,有必要吗?我是否错过了可能从 Objective-C 概念或框架调用的内存管理之类的东西?

【问题讨论】:

  • 并且你可以在实现文件的类类别中声明属性,这样这些属性就不会暴露为公共方法。
  • 另请注意,Apple 非常不鼓励在 ivars 前加上下划线,这可能会导致问题发生。我认为这是因为他们自己的内部类使用它们来避免名称冲突。

标签: iphone


【解决方案1】:

正如Jeremie Wekdin 提到的那样,我的问题以某种方式重复。类似的问题和答案确实表明,在使用 nib/xib 文件的情况下,需要考虑内存问题。

总之Cocoa会先寻找setOutletName,并使用属性方法设置UI控件对象;否则,Cocoa 将直接设置为类成员变量并保留它。这意味着归档对象应该在 dealloc 方法中释放。

没关系。但是,对于我的问题,我的字段变量的名称与其对应的属性名称不同,例如 _firstName 和 firstName。在这种情况下,我认为 Cocoa 不够聪明,无法弄清楚从 nib/xib 检索到的属性方法和对象直接设置为类成员。

为了验证它,我覆盖了 setter:

// in .m file
@implementation MyViewController {
@synthetic firstName = _firstName;
- (void) setFirstName:(UILabel*) value {
   NSLog("_firstname: %@", _firstName);
   [_firstname autorelease];
   _firstName = [value retain];
}

然后我加载我的视图,日志消息没有显示在 XCode 的输出控制台中。但是,如果我保持变量名和属性名相同。我确实看到 setter 被称为:

// in .h
@interface MyViewController : UIViewController {
IBOutlet UILabel* firstName;
...
}

@property (nonatomic, retain) UILabel* firstName;
...
@end

// in .m file
@implementation MyViewController {
@synthetic firstName;
- (void) setFirstName:(UILabel*) value {
   NSLog("firstName: %@", firstName);
   [firstName autorelease];
   firstName = [value retain];
}
...
@end

在输出控制台中,当视图显示时,我看到:

firstName: (null)

正如重复 QA 所建议的,我阅读了Appl's Resource Programming Guide。在Nib 对象生命周期对象加载过程和#3 Outlet 连接部分中找到文档。您应该看到 Mac OS X 和 iPhone OS 有不同的方式将插座连接到对象。 "在 iPhone OS 中,nib 加载代码使用setValue:forKey: 方法重新连接每个插座"

所以我尝试了以下代码:

@implementation MyViewController {
@synthetic firstName = _firstName;
- (void) setValue:(id) value forKey:(NSString*) key {
   NSLog("forKey: %@; value: %@", key, value);
   if ([key isEqualToString:@"_firstName"])
     // It should then call the accessor or property 
     // self._firstName = value;
     // to set value, like the follow codes in the setter:
     [_firstName autorelease];
     _firstName = [value retain];
   }
   ...
}
...
@end

我再次重新编译了我的代码,我确实看到了所有属性设置器调用,包括键 _firstName。续苹果文档:

“该方法 (setValue:forKey:) 类似地寻找合适的访问器方法,并在失败时使用其他方法。”

这解释了为什么在我的情况下(属性名称与出口变量名称不同)该属性由 Cocoa 调用。

总之,当 IBOutlet 和 nib/xib 用于字段控件(作为加载视图的一种方式)时,存在内存问题。最好让 Cocoa 找出定义的访问器或属性来设置字段变量,该变量处理保留对象。如果您为 IBOutlet 字段变量定义属性,则两者应具有相同的属性。因此,这些代码可以在 Mac OS X 和 iPhone OS 中运行。

【讨论】:

    猜你喜欢
    • 2011-03-26
    • 2010-11-16
    • 2011-12-19
    • 2012-03-06
    • 2011-04-13
    • 2020-07-17
    • 1970-01-01
    • 2019-09-21
    • 1970-01-01
    相关资源
    最近更新 更多