【问题标题】:Does omitting the declaration of ivars for properties might cause trouble or leaks?省略属性的 ivars 声明是否会导致麻烦或泄漏?
【发布时间】:2011-11-24 23:22:00
【问题描述】:

我开始为 iOS4 学习和开发,所以我只是跳过了旧的 ivar 声明约定,开始使用纯属性,甚至没有声明 ivar。一切都很顺利,我什至在应用商店发布了我的第一个自制应用。但后来在我的开发公司,人们告诉我,他们仍在使用旧的约定,并用下划线的名称声明 ivars,使用属性并合成它们(参见最后的示例)。他们还说,他们仅在需要外部访问 ivars 时才使用属性,而对于内部访问,他们使用直接 ivars(用于自定义类)。有人告诉我,他们这样做是因为他们遇到了一些奇怪的泄漏,有时会出现在使用自定义类并在 viewDidUnload 中取消它们的属性时(因为将 nil 设置为属性有时不会释放那些 ivar 对象)

只是想知道为什么我在使用属性和综合时要费心使用 ivar 声明来完成所有需要的事情。我什至可以直接使用他们的名字访问 ivars,而无需在 dealloc 中使用 self。那么,是否有人对此有问题,或者你们中的许多人仍然坚持旧的声明约定?

@interface ContactModel : NSObject {

  NSString *_firstName;
}

@property (nonatomic, retain) NSString *firstName;

@end

@implementation ContactModel

@synthesize firstName = _firstName;

-(void)dealloc{
  [_firstName release];
  [super dealloc];
}
@end

还应注意,Apple 在生成主应用程序委托类文件并合成 window=_window 时仍使用旧的声明样式。嗯,目前,我对我应该采取什么约定有点困惑,所以欢迎任何想法:)

【问题讨论】:

标签: iphone objective-c properties


【解决方案1】:

在现代运行时中,您不需要 ivar 声明,但综合 a=_a 仍然有助于区分 self.a(访问器)和 _a(直接访问)。如果@property/@synthesize 泄漏了,我想我们现在应该知道了。

仅当您想要@protected 访问(仅访问子类)或支持旧运行时时,AFAIK 使用 ivars 而不是属性才有用。

在 dealloc 中,无论您使用 ivar 声明和@properties,都应该直接释放属性,也可以选择使用you can nilnot

【讨论】:

  • 谢谢。但是当 a=_a 有用时,我的意思是访问 self.a 和直接访问 _a 的用例是什么?理论上,您应该始终使用封装并保护 ivars 不被直接访问(至少理论上,因为我知道所有 ivars 都是相当公开的)
  • 使用下划线只是一种命名约定,表示 _a 是直接访问。当您想避免访问器中的代码会导致触发通知等副作用时,您可以使用直接访问。
  • 如果一个对象注册到通知,那么使用直接访问更改是否可以避免通知?我一直认为这与使用格式无关。
  • 在 KVO 中运行时 overrides the setter code to post notifications 给观察者。但是您可以使用直接变量访问来解决它。这可能有用的一个场景是:我想在设置变量时预加载相关数据,除非我将它设置为 nil。
【解决方案2】:

我喜欢“旧方式”,因为我喜欢一致性和(更重要的是)封装。

一致性

就我个人而言,我只是想通过观察一个地方来了解对象的大小和复杂性。

例子:当你实现dealloc时,你喜欢引用多个地方吗?不是我。它比必要的复杂。我不想通过从所有 ivars 和属性创建一个集合来弄清楚我需要清理什么。仅靠属性是不够的,因为它们还会出现在多个地方(接口、私有类别)=\

所以较小的邪恶 imo 是声明 ivars,这样所有东西都在一个地方,您可以快速参考对象的复杂性(以及一些代码生成器的良好输入)。

封装

当您看到大多数对象的 ivars/属性可见且可读取/可写的程序时……这不是 OOD,而是一团糟。当您需要礼貌地描述它时,它是反模式'Object Orgy'。不幸的是,它在 objc 程序中相对常见(部分原因是语言/运行时限制)。

带有前缀下划线的 ivars:就个人而言,我在 objc 中不使用该约定。如果他们的代码是这样写的,那就去吧(没什么大不了的)。

他们还说,他们仅在需要外部访问 ivars 时才使用属性,而对于内部访问,他们使用直接 ivars(用于自定义类)。

是的 - 这是封装尝试进入图片的地方。顺其自然,接受适当的封装。

我被告知他们这样做是因为他们遇到了一些奇怪的泄漏,有时会出现在使用自定义类并在 viewDidUnload 中取消它们的属性时(因为将 nil 设置为属性有时不会释放那些 ivar 对象)

理想情况下,他们会为您提供更好的解释(并在当时找到具体问题的根源)。

很可能他们的神秘程序与其成员(数据)、接口及其执行没有足够清晰的区别。当这些重叠时,失去所有权的情况并不少见。这种情况是混乱和/或超出预期的实施的一般迹象。如果你正确地组织/编写类,ivar/property 跟踪非常简单(大概是通过支持封装而取得进展)。同样,protected 是默认可见性;我建议将 private 作为您的默认设置。

只是想知道为什么我在使用属性和综合时要费心使用 ivar 声明来完成所有需要的事情。我什至可以直接使用他们的名字访问 ivars,而无需在 dealloc 中使用 self。那么,是否有人对此有问题,或者你们中的许多人仍然坚持旧的声明惯例?

  • 设计良好的程序不是由数据 blob(具有公共或属性可访问变量)组成的。
  • 在大多数情况下,状态(例如 ivars)不应直接映射到接口。
  • 保持您的数据和实施对他人隐藏。
  • 即使是“私有”属性也可能是一个简单的错误来源(它们的选择器可能会被执行或覆盖)。
  • 当 private 是您的默认设置并且 ivar 确实无法从外部访问时,您可以减少很多的复杂性。

所以...我认为他们提出这个请求是为了通过减少对状态的外部暴露并最终减少程序的复杂性来简化您的生活。他们承认过去曾遇到过问题,并试图使用封装来降低复杂性和出错的机会。对他们有好处。

我知道,有些程序员只是喜欢所有公开可见和可变的东西 - 编写程序来支持这种复杂程度并不是对时间的有效利用,而现实是大多数人这样做 那样写没有远见或耐心来正确地写出这样的程序,然后它会引起其他人的头疼。当然,它在过去可能对您有用,但这是一种幼稚的方法,当您与团队合作时,您没有编写所有程序的奢侈。因此,您不能假设他们已经完整阅读并理解了您编写的每个程序。

尽可能隐藏你的程序,使你的程序易于使用/防错,并使它们与你团队的风格保持一致。

(技术上还有一些额外的好处,我不会在这里详细说明)

【讨论】:

  • 很好的答案。我不知道为什么当人们开始用 Objc 编程时,他们忘记了所有关于封装的事情
猜你喜欢
  • 2015-08-22
  • 1970-01-01
  • 2013-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-05
  • 1970-01-01
相关资源
最近更新 更多