6

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

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

为什么或为什么不使用私有财产?

4

7 回答 7

7

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

  • 正如您所说,使用属性将允许您轻松使用访问器方法,这些方法除了访问变量之外还可以进行一些额外的编码。
  • KVO不适用于 ivars。
  • 使公共只读属性仅对实现进行读写,以便在 getter 之外合成一个 setter(正如 Brad 指出的那样)
  • 个人喜好、习惯或懒惰(财产是公共的,但改为私人的)。
于 2013-11-14T16:24:44.437 回答
1

IMO OP 询问为什么将一些 ivars 放在接口中,而将一些 ivars 放在实现中。一个附带问题是为什么属性。

  1. 重点是封装。仅将那些打算在类外设计使用的东西放在公共接口 (.h) 文件中。将那些设计为仅用于实现 (.m) 文件中的实现。那就是任何未公开公开的内容都可以在以后更改而不会影响班级的用户。

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

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

于 2013-11-14T16:47:18.303 回答
1

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

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

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

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

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

于 2013-11-14T16:25:32.200 回答
0

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

于 2013-11-14T16:34:09.553 回答
0

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

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

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

于 2013-11-14T16:24:12.193 回答
0

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

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

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

这是一个简单且足够好的系统一段时间......

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

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

于 2013-11-14T16:32:30.683 回答
-1

这真的很简单。

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

@interface MyViewController ()

@property (nonatomic, strong) NSString *myPrivateStringProperty;

@end

@implementation MyViewController

@end

在这里,该属性只能在您的 .m 中访问。

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

@interface MyViewController : UIViewController

@property (nonatomic, strong) NSString *myPublicStringProperty;

@end

在这里,您可以在课堂外访问该属性。

于 2013-11-14T16:28:14.173 回答