属性vs实例变量,差类封装?

时间:2013-10-18 20:46:45

标签: ios objective-c

除非需要,否则我不喜欢暴露类变量。在我看到的大多数objective-c代码中,变量被声明为属性,即使它们永远不会被外人使用。

@interface DetailViewController : UIViewController {
    __weak IBOutlet UILabel *name;
}

VS

@interface DetailViewController : UIViewController

@property (weak, nonatomic) UILabel *name;

作为软件工程专业的学生,​​这对我来说是一个非常糟糕的违反封装等原则的行为,可能会导致大型项目中不必要的耦合。

我确实理解使用属性的KVC方面,但不知道为什么会暴露出明显只是在类内部使用的变量,例如上面的UILabel。

有人可以解释为什么这是在iOS上使用Objective-C时的首选方法吗?

3 个答案:

答案 0 :(得分:4)

属性封装了iVar的内存管理(例如,分配,保留,复制,强,弱),而直接访问iVar(实例变量)却没有。这大大减少了内存错误。

非公开属性可以在.m的顶部声明,因此没有理由将它们放在标题中:

@interface DetailViewController ()
@property (weak, nonatomic) NSString *name;
@end

属性执行创建可以访问的ivars。对于上面的示例,使用显式合成的属性,ivar将命名为name,而隐式合成的合成属性将具有前导下划线_name

IBOutlet在标头中声明,即使其他类不需要访问它们,因为它们是必需的,以便Interface Builder连接到它们,并且nib加载系统可以填充插座。 IBOutlet通常是视图,例如UILabel

编辑:

关于IBOulet的前一段是Xcode 3及更早版本所需的遗留方法。但是,由于InterfaceBuilder与IDE的其他部分更紧密地集成,Xcode的新版本可以使用实现文件中定义的插座,就像上面的属性一样。

答案 1 :(得分:1)

你看到的是旧式。早期的Objective-C编译器需要您在接口中声明实例变量。但是,默认情况下它们是@protected,因此不是每个人都可以使用它们。

目前的最佳做法是你根本不使用属性来声明实例变量,除非你需要声明它们(如果你有一个readonly属性的自定义getter,或者readwrite属性的自定义getter和setter,没有自动生成实例变量),你在.m文件中声明它们,除非有人确实需要访问它们,你在.m文件中声明属性和方法,除非有人需要访问它们,并且你没有声明方法,除非需要。

在头文件中将属性声明为readonly也很常见,并在实现中将其重新声明为读/写。

换句话说,隐藏你可以隐藏的东西。

答案 2 :(得分:0)

第一个示例表明您要将标签用作Xib或Storyboard的插座。这个答案为这个案例提供了一些启示:https://stackoverflow.com/a/1236985/171933

但是,通常,您不需要将内部实例变量声明为属性。实际上,您可以将它们完全移出标题,方法是将它们放入.m文件中,如下所示:

@implementation DetailViewController 
{
    NSInteger _someValue;
    UILabel *_someLabel;
}

通过这种方式,您实际上只能将标题中的内容保留在外部可见的内容中。而这些东西通常都是属性或普通的旧方法。