Objective c 目标C:私有变量与私有属性

Objective c 目标C:私有变量与私有属性,objective-c,Objective C,对我来说,作为Objective-C开发者的过去很简单。类需要公共的每个字段都是属性,每个私有字段都是实例变量,没有getter或setter。但我经常看到人们在实现文件中使用私有接口来声明私有属性。有人告诉我,这就是现在做事的方式 虽然这样做很好,但我很难看到它的优点。只要我不需要getter或setter中的一些逻辑,我就会继续使用实例变量来处理所有非公共的事情。我必须承认使用了一个属性,然后使用关键字self使代码更具可读性。您可以查看属性是否属于类,或者它是否只是方法中的局部变量,但这不

对我来说,作为Objective-C开发者的过去很简单。类需要公共的每个字段都是属性,每个私有字段都是实例变量,没有getter或setter。但我经常看到人们在实现文件中使用私有接口来声明私有属性。有人告诉我,这就是现在做事的方式

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


为什么或者为什么不使用私有属性?

objective-c中的属性不仅仅是实例变量。它们是由实例变量支持的getter和setter方法的组合

通常,当人们在实现文件(私有类扩展名)中添加属性时,会将一个公开的
readonly
属性设置为
readwrite
属性,以便设置它并保留所有属性语义,如键值编码。属性还负责为您保留副本


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

在IVAR上使用(私有)属性有几个原因

  • 正如您所说,使用属性将允许您轻松地使用访问器方法,这些方法除了访问变量之外,还可以执行一些额外的编码
  • 不适用于IVAR
  • 为实现生成一个公共readonly属性readwrite only,以便在getter之外合成一个setter(正如Brad所指出的)
  • 个人偏好、习惯或懒惰(财产为公共财产,但改为私人财产)

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

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

但是,将这些变量私有化是一个优势,即在类扩展中声明它们,如下所示:

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

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

@interface MyViewController ()

@property (nonatomic, strong) NSString *myPrivateStringProperty;

@end

@implementation MyViewController

@end
在这里,该属性只能在.m中访问

如果要使用公共
@属性
,请在.h中添加此属性:

@interface MyViewController : UIViewController

@property (nonatomic, strong) NSString *myPublicStringProperty;

@end

在这里,属性可以在您的类之外访问。

这只是一个封装问题,您可以拥有许多不同级别的私有性

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

@interface MyClass : NSObject
{
//every ivar that MyClass adds to NSObject must be here
}
在一段时间内,这是一个简单且足够好的系统

即使是私有IVAR也必须声明,尽管编译器不允许您在错误的范围内访问它们

@interface MyClass : NSObject
{
 @private
 id someObj;
}
此可见性说明符限制访问,例如:

//另一类

 + (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,需要在那里工作的库需要采用旧的方式。

良好地使用属性可能更“方便”(至少因为您不必担心在KVO可访问属性的情况下忘记调用willChange/didChange)而且,毫无疑问,使用IVAR而不是属性更快。因此,我建议使用属性,除非你真的关心每秒帧数。看看是否是这样。

我的OP询问为什么在接口中放置一些IVAR,在实现中放置一些IVAR。一个次要问题是为什么要使用属性

  • 关键是封装。只在公共接口(.h)文件中放置那些设计用于类外的东西。将那些设计用于实现的东西放置在实现(.m)内任何未公开的内容都可以在以后更改,而不会影响类的用户

  • 属性为关联的ivar提供setter/getter方法。在当前objective-c编译器中,如果没有
    @synthesis
    语句,编译器将自动生成ivar,该ivar的名称与以下划线(\ux)为前缀的属性的名称相同。getter/setter还支持KVO,这可能是一个加号,具体取决于您的使用情况。请注意,可以在接口文件中声明readonly属性,并在实现文件类扩展名中声明readwrite属性


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

    明白了。你可以有一个只读的pu