首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ObjectiveC ivars或@property

ObjectiveC ivars或@property
EN

Stack Overflow用户
提问于 2011-08-04 21:37:12
回答 4查看 2.5K关注 0票数 6

在iPhone上工作,在经历了许多令人头疼的问题和内存问题之后,我从其他示例中意识到,我们没有必要为我们在头文件中定义的每个实例变量创建@属性。实际上,我发现在类中的任何地方使用ivars都很容易分配和释放它,因为@properties我必须使用autorealese,否则我就会遇到严重的问题,并且要注意分配的方式。

例如,对于下面的对象,@properties(保留/复制..)在许多示例中没有在头部中使用;

代码语言:javascript
复制
{
NSURLConnection *connection;
NSMutableData *xmlData;
NsMutableString *string
} 

但对于某些字符串或对象类型使用@properties,我知道当我们设置@property时,cocoa会创建一些setters来处理对象的重新分配和保留。但似乎对于xmlData或连接实例变量,我们不需要它们,它们的工作方式是这样的。

在决定是创建@property还是只使用简单的ivars时,有没有一些我可以记住的参考指南?

我在使用属性时唯一的问题不是因为我懒于定义它,但是当我在代码中仔细地分配和初始化它们时,我必须使用autorelase,并且感觉我不能控制何时释放重置并再次分配它,它让我又多了一件事要担心何时、何时以及如何释放、重置它。我发现anything..or我可以随时随地轻松地分配和释放,而不用担心ivars,我在这里遗漏了其他东西。

Tnx

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-08-04 23:17:42

似乎仍然有一些关于属性的误解。

我们不需要为我们在头文件中定义的每个实例变量创建@

对,是这样。您可以在实现文件中直接使用私有实例变量。但是,由于合成的属性附带了免费的内存管理,因此您最好利用这一点。我的经验法则是直接使用ivar,直到我第一次发现自己在写:

代码语言:javascript
复制
[ivar release];
ivar = [newIvar retain];

正如萨姆所说,如果使用iVar == newIVar,就已经有了一个潜在的bug。在这一点上,我从直接使用ivars切换到创建属性。但是,我将新属性的声明放在实现文件的class extension中。这意味着该属性正式不是公共接口的一部分(如果意外使用,将导致编译器警告)。

当我们设置@property cocoa时,

会创建一些setters,这些getter处理对象的重新分配和保留。

实际上,不是。@属性只是声明了一个属性。为了自动生成getter和setter,您需要@synthesize它。你也可以编写你自己的setter和setter,它们甚至不需要引用真正的ivar。

从技术上讲,您不应该在init或dealloc方法中使用该属性,因为子类可能已经覆盖了它们,或者(在dealloc中)您可能会触发KVO通知。

来自Sam的回答和评论

如果您无论如何都想要一个属性,则可以在实现文件的顶部使用私有接口

正如我上面所说的,私有类别已经被类扩展所取代(这与类扩展非常相似,但允许您将方法的实现放在主类实现中)。

如果您想要获得使用点符号速记的好处,请使用

我们中的一些人会争辩说,点符号没有任何好处。这是对结构成员语法的一种无端和不必要的污染。但是,点符号与@property声明无关。您可以对任何访问器使用点表示法,无论它们是如何声明的,只要它们遵守模式-foo-setFoo:

票数 6
EN

Stack Overflow用户

发布于 2011-08-04 21:40:13

只为需要从类外部访问的变量创建属性。内部使用的任何类变量都不需要定义getter/setter。

一般来说,丰富的属性表示高耦合和差的封装性。您应该限制您的类在接口中公开的变量。

编辑以回应评论:

使用属性而不是直接访问可能是的首选,因为它为您提供了简单的内存管理。例如:

代码语言:javascript
复制
// interface
@property (retain) Object *someVar;     

// implementation
self.someVar = otherVar;

等同于

代码语言:javascript
复制
// implementation
if (_someVar != othervar)
{
    [_someVar release]
    _someVar = [otherVar retain];
}

但是,您不应该在接口中不必要地公开var,因为它会让人们以错误的方式使用类。

如果您无论如何都想要一个属性,可以在实现文件的顶部使用私有接口

代码语言:javascript
复制
@interface TheClass(Private)
    // private stuff
@end
票数 4
EN

Stack Overflow用户

发布于 2011-08-04 22:24:45

长期以来,直接访问ivars已经成为一种习惯。也就是说,尽管许多属性都是类,然后属性提供了保护,防止保留/释放问题,但从同一个类中可以很好地处理IMO。

然而,最好将大多数ivars封装到属性中,特别是那些具有保留/释放语义的属性,但也包括那些需要特殊处理的属性,即您为其编写自己的处理程序,而不是使用合成的处理程序。这样,你就可以过滤对某些ivars的访问,或者甚至创建没有任何后备存储的属性,这些属性只是其他属性的“别名”,例如,Angle类具有度属性,该属性以度为单位提供角度,弧度属性以弧度表示相同的角度(这是一个简单的转换),或者是一个必须进行字典搜索才能找到它的值的属性,等等。

在Delphi (AFAICT)中,它是最早将属性作为语言构造的语言之一,习惯上将所有的ivar都包装在属性中(但不是所有的都必须是公共的),并且有许多这样的“不真实”(我在这里故意避免使用术语“虚拟”)属性,即那些只在代码中实现的属性,而不仅仅是ivar的getter和setter。

属性提供encapsulationabstraction和一定程度的保护,防止某些常见的错误,这就是为什么它们比直接访问ivars,IMO更受欢迎的原因。

加法

声明和实现(通过@synthesize或者使用自定义的setter和getter)公共属性为每个 ivar是没有意义的。只公开暴露别人可能需要的东西。内部状态也可以通过属性向您自己的代码公开,但这应该通过实现文件中的私有或空类别来完成。这样,您就可以自动处理保留/释放,并且仍然不会向公众公开它们。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6942439

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档