属性与实例变量,类封装不佳



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

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

@interface DetailViewController : UIViewController
@property (weak, nonatomic) UILabel *name;

作为一名软件工程专业的学生,这对我来说是相当糟糕的,违反了封装等原则,并可能导致大型项目中不必要的耦合。

我确实了解使用属性的 KVC 方面,但不了解为什么要公开显然只在类内部使用的变量,例如上面的 UILabel。

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

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

非公共属性可以在.m的顶部声明,因此它们没有理由出现在标头中:

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

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

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

编辑:

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

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

当前的最佳实践是,你根本不声明实例变量,而是使用属性,除非你需要声明它们(如果你有一个只读属性的自定义 getter,或者有一个读写属性的自定义 getter 和 setter,则不会自动生成实例变量),除非有人真的需要访问它们,否则你在 .m 文件中声明它们, 在 .m 文件中声明属性和方法,除非有人需要访问它们,并且除非需要,否则根本不声明方法。

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

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

第一个示例指示您希望将标签用作 Xib 或情节提要的出口。这个答案揭示了这种情况的一些情况:https://stackoverflow.com/a/1236985/171933

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

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

这样,您实际上只能保留标题中应该对外部可见的内容。这些东西通常是属性或普通的旧方法。

最新更新