Objective-C中的属性和实例variables
我对Objective-C中的属性和实例variables感到困惑。
我是通过Aaron Hillegass的“Mac OS Xcocoa编程”的一半,一切都是合乎逻辑的。 你会像这样声明一个类:
@class Something; @interface MyClass : NSObject { NSString *name; NSArray *items; Something *something; IBOutlet NSTextField *myTextField; } @property (nonatomic, retain) NSString *name; @property (nonatomic, retain) NSArray *items;
-
由于其他对象需要操作我们的
name
和items
实例variables,因此我们使用@property
/@synthesize
为它们生成访问器/修改器。 在我们的类中,我们不使用访问器/增变器 – 我们只是直接与实例variables交互。 -
something
只是一个实例variables,我们将在我们的类中使用,因为没有其他人需要使用它,所以我们不会为它创build一对访问器和增变器。 -
我们需要在UI中与文本字段交互,所以我们为它声明一个
IBOutlet
,连接它,然后完成。
一切都很合乎逻辑
但是,在iPhone世界里,事情似乎有所不同。 人们为每个实例variables声明属性,为IBOutlets
声明属性,并使用访问器/增变器与类中的实例variables进行交互(例如,它们会写[self setName:@"Test"]
而不是name = @"Test"
) 。
为什么? 到底是怎么回事? 这些差异是iPhone特有的吗? 为所有实例variables声明属性,为IBOutlets
声明属性以及在你自己的类中使用访问器/修改器有什么优势?
在iPhone世界里,没有可用的垃圾回收器。 你必须仔细pipe理内存与引用计数。 考虑到这一点,请考虑以下区别:
name = @"Test";
和
self.name = @"Test"; // which is equivalent to: [self setName: @"Test"];
如果直接设置实例variables,而没有事先考虑,则将丢失对前一个值的引用,并且无法调整其保留计数(应该手动release
它)。 如果通过属性访问它,则会自动为您处理,同时递增新分配的对象的保留计数。
根本的概念不是iPhone的具体情况,但在没有垃圾收集器的环境中,它变得至关重要。
属性用于为实例variables生成访问器,没有魔法发生。
您可以手动执行相同的访问器。
你可以在Aaron Hillegass的书中find3个成员variables的内存pipe理策略的例子。 他们是assign/copy/retain
。 您可以根据给定的variablesselect其中的一个。
我假设你了解Objective-C中的内存pipe理
访问者隐藏每个variables的内存pipe理的复杂性和差异。
例如:
name = @"Test"
是一个简单的赋值, name
现在持有对NSString @"Test"
引用。 但是,您可以决定使用copy
或retain
。 无论您select访问器的哪个版本的内存pipe理都隐藏了复杂性,并且始终使用(或类似)访问该variables:
[self setName:@"Test"] [self name]
现在setName:
可以使用assign/copy or retain
,不必担心。
我的猜测是,iPhone教程使用属性,使新开发人员更容易跳过内存pipe理(即使它可以方便地生成具有属性的适当的访问器,而不是每次手工实现它们)。
但是,在iPhone世界里,事情似乎有所不同。 人们为每个实例variables声明属性,为
IBOutlets
声明属性,并使用访问器/增变器与类中的实例variables进行交互(例如,它们会写[self setName:@"Test"]
而不是name = @"Test"
) 。
这不是iPhone特有的。 除了init
方法和dealloc
方法外,最好总是使用你的访问器。 主要的好处,特别是在Mac(与cocoa绑定),是使用您的访问者意味着免费的KVO通知。
人们为什么“为每个实例variables声明属性”的原因很可能是他们所有的实例variables都是他们想要公开的属性。 如果他们有一些他们想保持私有的东西,他们不会在头文件中为它声明一个属性。 (但是,他们可能会在实现文件的类扩展中为它创build一个属性,以获得上述免费的KVO通知。)
在我看来,宣布网点的属性是矫枉过正的。 我不明白这一点。 如果你没有创build属性,那么nib加载器将通过直接的实例variables访问来设置sockets,这对于这个任务来说是很好的。
我认为现代化发展已经非常有力地确定,确定和应用最佳实践。
在这些最佳实践中,我们发现连续性和一致性。
除了在init
和dealloc
方法中争论使用访问器之外,访问者通常应该始终使用访问器(在一个类的内部和外部)来获得它们提供的好处,包括封装 ,多态var实现(它们都允许抽象和重构)并促进这些最佳做法的连续性和一致性。 面向对象的语言的基本好处是以这种方式做事情,并充分利用语言的能力。 任何高级程序员通常都会certificate,在编码方面始终保持一致是经常被忽略的好处。
你可以这样写
//MyClass.h @class Something; @interface MyClass : NSObject @property (nonatomic, strong) NSString *name; @property (nonatomic, strong) NSArray *items; @end //MyClass.m @interface MyClass() @property (nonatomic, strong) IBOutlet NSTextField *myTextField; @property (nonatomic, strong) Something *something; @end