私人和公共成员如何在Objective-C中实施?

我有一些关于在工作中使用属性和实例variables的讨论,所以我想find一个wiki的答案。 现在,我知道在Objective-C中没有真正的私有成员types,一切都非常公开。 不过,我有点担心我们应该devise我们的class级,也遵守面向对象的原则。 我想听听这三种devise方法的意见:

答:根据各个职位甚至到斯坦福大学新的iPhone开发课程,你应该随时随地使用属性。 然而,恕我直言,这种方法制动OOP的devise原则,因为在这种情况下,所有成员公开。 为什么我需要将所有内部/本地实例variables发布到外部? 另外,如果你通过属性使用合成的setter,而不是直接使用本地ivar,那么就会有一些(但仍然)开销。 这是一个示例:

//==== header file =====// @interface MyClass : NSObject @property (nonatomic, retain) NSString *publicMemberWithProperty; @property (nonatomic, retain) NSString *propertyForPrivateMember; @end 

B.另一种方法是在头文件中声明ivars(不声明相对属性)私有成员,并在同一个头文件中为公共成员声明纯属性(不声明相对ivars)。 在这种情况下,Ivars将直接在课堂上使用。 这种方法是有道理的,但不能使用属性的所有好处,因为我们在设置新值之前手动释放旧值。 这是一个示例:

 //==== header file =====// @interface MyClass : NSObject{ NSString *_privateMember; } @property (nonatomic, retain) NSString *publicMemberWithProperty; @end 

C.为头文件中的公共成员声明纯属性(不声明相对ivars),并在实现文件的私有接口中为私有成员声明纯属性(不声明相对ivars)。 恕我直言,这个方法比第一个更清楚,但同样的问题仍然存在:为什么我们必须有内部/本地成员的财产? 这是一个示例:

 //==== header file =====// @interface MyClass : NSObject @property (nonatomic, retain) NSString *publicMemberWithProperty; @end //==== implementation file =====// @interface MyClass() @property (nonatomic, retain) NSString *propertyForPrivateMember; @end 

这个决定的自由让我有些烦恼,我想从各个来源得到有关应如何处理的确认。 但是,在苹果文档中我找不到这样严格的声明,所以请发布一个链接到苹果文档,如果有的话,或任何其他理论,清除这一点。

通过使用类扩展你可以拥有私有属性。

类扩展语法很简单:

.m文件里面有这个类,创build一个未命名的类别:

。H

 @interface OverlayViewController : UIViewController <VSClickWheelViewDelegate> - (IBAction)moreButtonClicked:(id)sender; - (IBAction)cancelButtonClicked:(id)sender; @end 

.M

 #import "OverlayViewController.h" @interface OverlayViewController () @property(nonatomic) NSInteger amount; @property(retain,nonatomic)NSArray *colors; @end @implementation OverlayViewController @synthesize amount = amount_; @synthesize colors = colors_; //… @end 

现在,您已经获得了私人会员的所有属性,而不会将其暴露给公众。 合成的属性不应该写入getter / setter,因为编译器在编译时会创build更多或更less的内容。

请注意,此代码使用合成的ivars。 头部没有伊娃尔声明是必要的。

有一个很好的cocoawithlove文章 ,关于这个方法。

你也问为什么要使用私有ivars的属性。 有几个很好的理由:

  • 属性照顾所有权和内存pipe理。
  • 在将来的任何时候你都可以决定写一个自定义的getter / setter。 即重新加载一个tableview,一旦NSArray伊娃新设置。 如果您因此而使用属性,则不需要其他更改。
  • 键值编码支持属性。
  • 公共只读属性可以重新声明为私有读写属性。

编辑
由于LLVM 3也可以在类扩展中声明ivars

 @interface OverlayViewController (){ NSInteger amount; NSArray *colors; } @end 

甚至在执行块

 @implementation OverlayViewController{ NSInteger amount; NSArray *colors; } //… @end 

请参阅“WWDC2011:Session322-Objective-C深度parsing”(〜03:00)

真的没有一个干净,安全,零开销的解决scheme,这是由语言直接支持。 许多人对目前的能见度特征满意,而许多人则认为他们缺乏。

运行时可以 (但不)与ivars和方法做这个区别。 一stream的支持将是最好的,国际海事组织。 在那之前,我们有一些抽象的成语:

选项A

不好 – 一切都可见。 我不同意这是一个好方法,那不是OOD(IMO)。 如果一切都可见,那么你的class级应该:

  • 支持客户如何使用您的class级的所有情况(通常不合理或不合意)
  • 或者通过文档向他们提供大量的规则(doc更新可能会被忽视)
  • 或访问者应该没有副作用(而不是OOD,并经常转换为“不要覆盖访问者”)

选项B

有选项A的缺陷,和选项A一样,成员可以通过键来访问。

选项C

这比较安全一点。 像所有其他人一样,你仍然可以使用键控访问,子类可以覆盖你的访问者(即使不知不觉)。

选项D.

一种方法是将你的类写成一个实现types的包装器。 您可以使用ObjCtypes或C ++types。 在速度很重要的地方你可能会喜欢C ++(在OP中提到过)。

一个简单的方法将采取以下forms之一:

 // inner ObjC type @class MONObjectImp; @interface MONObject : NSObject { @private MONObjectImp * imp; } @end // Inner C++ type - Variant A class MONObjectImp { ... }; @interface MONObject : NSObject { @private MONObjectImp imp; } @end // Inner C++ type - Variant B class MONObjectImp; @interface MONObject : NSObject { @private MON::t_auto_pointer<MONObjectImp> imp; } @end 

(注意:由于这是最初编写的,因此已经介绍了在@implementation块中声明ivars的能力,如果不需要支持较老的工具链或“易碎”的32位OS X,则应该在那里声明C ++typesABI)。

C ++变体A不像其他变体那样“安全”,因为它需要客户机可见的类声明。 在其他情况下,您可以在实现文件中声明和定义Imp类 – 从客户端隐藏它。

然后你可以暴露你select的界面。 当然,如果客户真的想通过运行时,仍然可以访问您的成员。 这对于他们安全地使用ObjC Imptypes来说是最容易的 – objc运行时不支持成员的C ++语义,所以客户端会询问UB(IOW它是运行时的所有POD)。

ObjC实现的运行时成本是编写一个新的types,为每个实例创build一个新的Imp实例,并且消息传递量增加了一倍。

除了分配之外,C ++types几乎没有任何成本(变体B)。

选项E

其他方法通常将ivars从接口分离出来。 虽然这是一件好事 ,但ObjCtypes也是非常不寻常的。 ObjCtypes/devise通常与他们的访问者和访问者保持密切的关系 – 所以你将面临来自其他一些开发者的阻力。

与C ++类似,Objective C提供公共,私有和受保护的作用域。 它还提供了一个与Java中定义的包范围类似的包范围。 类的公共variables可以是程序中的任何地方的引用。 私有variables只能在声明它的类的消息中被引用。 它可以在属于同一类的ANY实例的消息中使用。 软件包范围与公共范围相似,即可执行文件或库。 根据Apple的文档,在64位体系结构中,在不同映像中定义的包范围variables将被视为私有variables。 variables作用域由@public,@ private,@protected和@package修饰符定义。 这些修饰符可以以类似于C ++或Java的方式使用。 在范围声明下列出的所有variables属于相同的范围。 另外,variables可以在声明范围的同一行上列出。

  @interface VariableScope : NSObject { @public int iVar0; @protected int iVar1; @private int iVar2; @package int iVar3; @public int iVar01, iVar02; @protected int iVar11, iVar12; @private int iVar21, iVar22; @package int iVar31, iVar32; } @end 

欲了解更多信息使用下面的链接

http://cocoacast.com/?q=node/100