Objective-C:私有变量VS私有属性

时间:2013-11-14 16:17:04

标签: objective-c

对我而言,Objective-C开发人员过去很简单。一个类需要公开的每个字段都是一个属性,每个私有字段都是没有getter或setter的实例变量。但更常见的是,人们在实现文件中使用私有接口来声明私有属性。我被告知这是现在做事的方式。

虽然这很好但我很难看到它的优点。只要我在getter或setter中不需要一些逻辑,我就会继续使用实例变量来处理所有不公开的事情。我必须承认使用属性然后使用关键字self使代码更具可读性。您可以查看属性是属于该类,还是属于方法中的局部变量,但这不是唯一的原因。

为何或为何不使用私人物业?

7 个答案:

答案 0 :(得分:7)

与ivars相比,使用(私有)属性有几个原因。

  • 正如您所说,使用属性将允许您轻松使用访问器方法,除了访问变量之外,还可以执行一些额外的编码。
  • KVO不适用于ivars。
  • 仅为实现创建一个公共readonly属性readwrite,除了getter之外还要合成一个setter(正如Brad所指出的那样)
  • 个人偏好,习惯或懒惰(财产是公开的,但已改为私人)。

答案 1 :(得分:1)

首先,如果您不需要私有属性,请不要使用属性:除非您希望以声明方式从编译器中获取某些特定行为,例如强制NSString复制赋值,否则没有任何好处使用属性。

此外,您不一定需要使用self来访问这些属性:当您自动或使用@synthesize关键字为您合成属性时,您会获得一个“支持”该变量的变量属性。分配该变量是访问该属性的完全合法方式,例如,当您想要将其显示为只读时。

然而,将这些变量设为私有是一个优点,即在类扩展中声明它们,如下所示:

@interface MyClass() { // <<== Note the () -- it's a class extension
   SomeOtherClass *privateIvar;
}

如果在类扩展中声明一个变量(在.m文件中而不是标题中),您将能够隐藏"SomeOtherClass"的标题,这在开发单个应用程序时不太重要,但是当你开始使用自己的类库进行开发时,它会变得非常有用。

答案 2 :(得分:1)

IMO OP正在问为什么在界面中放入一些ivars,在实现中放置一些。另一个问题是为什么属性。

  1. 重点是封装。只将那些东西放在公共接口(.h)文件中,这些文件应该由类外的设计使用。将那些按设计的方法仅用于实现(.m)文件中的实现。这是任何未公开的内容都可以在以后更改,而不会影响该类用户。

  2. 属性为关联的ivars提供setter / getter方法。在当前的objective-c编译器中,如果没有@synthesize语句,编译器将自动生成与前缀为下划线(_)的属性同名的ivar。 getter / setter也支持KVO,根据您的使用情况,这可能是一个加号。注意,可以在接口文件中声明一个属性readonly,并在实现文件类扩展中读取。

  3. 因此,目前的最佳做法是对所有ivars使用属性,如果属性设计为公共属性,则将属性语句放在接口文件中,如果设计为私有,则将属性语句放在类扩展的实现文件中。这提供了一个干净的接口文件,只公开公共方法和属性。

答案 3 :(得分:0)

objective-c中的

属性不是只是实例变量。它们是由实例变量支持的getter和setter方法的组合。

通常当人们在实现文件(私有类扩展)中添加属性时,将公共readonly属性设置为readwrite属性,以便他们可以设置它并保留所有属性语义,如key-价值编码。属性还会为您处理复制保留。

它只是一种将公共接口与实现分开的方法。

答案 4 :(得分:0)

这只是一个封装问题,你可以拥有许多不同程度的私密性......

最初在Objective-C中,运行时不支持在运行时向Object添加实际字段,因此每个iVar都必须在类中列出:

@interface MyClass : NSObject
{
//every ivar that MyClass adds to NSObject must be here
}

这是一个简单而且足够好的系统......

甚至必须声明私有iVars,尽管编译器不允许您在错误的范围内访问它们。

@interface MyClass : NSObject
{
 @private
 id someObj;
}

此可见性说明符限制访问,如:

// someotherclass.m

 + (void)doSomething
 {
     MyCLass * mc = [MyClass new];
     mc->someObj = [SomeOtherClass new]; // error cant access private variable...
 }

但你可能会用指针算术来实现它,所以为了混淆你会在类中看到这样的东西:

@interface MyClass : NSObject
{
 @private
 void * __reserved1;
 void * __private1;
}

这是非常好的混淆......

但等等.... 有更好的方式!

输入非脆弱的ABI

现在类只需要导出超类和公共接口。

@interface MyClass : NSObject
@property (readonly,retain) id someIVar;

并且其他类内容可以包含在类扩展中:

@interface MyClass ()
{
 id someObj;
}
@property (readwrite,retain) id someIVar;

请注意,这只适用于iPhone和64位OS X 32位OS X仍然是旧的ABI,需要在那里工作的库需要采用旧方法。

答案 5 :(得分:0)

使用属性可能更“方便”(至少因为您不必担心在KVO-able属性的情况下忘记调用willChange / didChange),毫无疑问,使用ivars而不是属性会更快。所以我建议使用属性,除非你真的关心每秒的帧数。如果是这种情况,请查看this awesome post

答案 6 :(得分:-1)

这很简单。

如果您想使用私有 @property,请在.m中添加此属性:

@interface MyViewController ()

@property (nonatomic, strong) NSString *myPrivateStringProperty;

@end

@implementation MyViewController

@end

此处,只能在.m。

中访问该媒体资源

如果您想使用公开 @property,请在.h中添加此属性:

@interface MyViewController : UIViewController

@property (nonatomic, strong) NSString *myPublicStringProperty;

@end

此处,您可以在课堂外访问该媒体资源。