私人和公共成员如何在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
欲了解更多信息使用下面的链接
- Objective-c中的自定义属性属性
- 当我重写Modern Objective-C中的setter和getters时,错误地访问生成的ivars
- Xcode 4在使用@属性时自动生成iVar,我可以在哪里find这个function的官方文档?
- 错误在Swift类:属性没有在super.init调用初始化 – 如何初始化需要使用self在他们的初始化参数
- iOS的MapKit拖动注解(MKAnnotationView)不再与地图平移
- 自动将属性值从一个对象复制到另一个不同types的对象,但协议相同(Objective-C)
- 如果我想为自己分配一个属性呢?
- 使用@property和@synthesise?
- 使用“copy”属性来维护一个不可变的NSString