Objective-C中的属性和实例变量

时间:2009-10-11 22:28:38

标签: objective-c cocoa cocoa-touch properties instance-variables

我对Objective-C中的属性和实例变量感到困惑。

我大约在Aaron Hillegass的“Mac OS X的可可编程”中途,一切都是合乎逻辑的。你会声明一个这样的类:

@class Something;

@interface MyClass : NSObject {
    NSString *name;
    NSArray *items;

    Something *something;

    IBOutlet NSTextField *myTextField;
}

@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSArray *items;
  • 由于其他对象需要操作我们的nameitems实例变量,我们使用@property / @synthesize为它们生成访问器/变更器。在我们的课程中,我们不使用访问器/ mutator - 我们只是直接与实例变量交互。

  • something只是我们将要在我们的类中使用的实例变量,并且由于没有其他人需要使用它,我们不会为它创建一对访问器和变换器

  • 我们需要与用户界面中的文字字段进行互动,因此我们为其声明IBOutlet,连接它,我们就完成了。

一切都非常符合逻辑。

然而,在iPhone世界中,事情似乎有所不同。人们为每个单个实例变量声明属性,声明IBOutlets的属性,并使用访问器/变异器与类中的实例变量进行交互(例如,他们会写[self setName:@"Test"]而不是name = @"Test")。

为什么呢?到底是怎么回事?这些差异是否与iPhone有关?声明所有实例变量的属性,声明IBOutlets的属性,以及在您自己的类中使用访问器/变换器有什么好处?

5 个答案:

答案 0 :(得分:29)

在iPhone世界中,没有可用的垃圾收集器。你必须通过引用计数仔细管理内存。考虑到这一点,请考虑以下区别:

name = @"Test";

self.name = @"Test";
// which is equivalent to:
[self setName: @"Test"];

如果您直接设置实例变量,而没有事先考虑,您将失去对先前值的引用,并且您无法调整其保留计数(您应手动release d)。如果您通过属性访问它,它将自动为您处理,同时增加新分配对象的保留计数。

基本概念不是iPhone特定的,但在没有垃圾收集器的环境中它变得至关重要。

答案 1 :(得分:6)

属性用于为实例变量生成访问器,没有任何魔法发生。

您可以手动实现相同的访问者。

你可以在Aaron Hillegass的书中找到3个成员变量记忆管理策略的例子。他们是assign/copy/retain。您可以根据给定变量的要求选择其中一个。

我假设您了解Objective-c中的内存管理...

访问者隐藏了每个变量的内存管理的复杂性和差异。

例如:

name = @"Test"

是一项简单的作业,name现在可以引用NSString @"Test"。但是,您可以决定使用copyretain。无论您选择哪种版本的内存管理访问者都隐藏了复杂性,您总是使用(或类似)访问变量:

[self setName:@"Test"] 
[self name]

现在setName:可能会使用assign/copy or retain,您无需担心。

我的猜测是,iPhone教程使用属性使新开发人员更容易跳过内存管理(即使用属性生成适当的访问器而不是每次手动实现它都很方便。)

答案 2 :(得分:3)

  

然而,在iPhone世界中,事情似乎有所不同。人们为每个单个实例变量声明属性,声明IBOutlets的属性,并使用访问器/变异器与类中的实例变量进行交互(例如,他们将编写[self setName:@"Test"]而不是name = @"Test")。

这不是特定于iPhone的。除init方法和dealloc方法外,最好始终使用您的访问者。主要的好处,特别是在Mac(使用Cocoa Bindings)上,使用您的访问器意味着免费的KVO通知。

人们“为每个单个实例变量声明属性”的原因很可能是他们所有的实例变量都是他们想要作为属性公开的东西。如果他们有想要保密的东西,他们就不会在头文件中声明它的属性。 (但是,他们可以在实现文件的类扩展中为它创建一个属性,以获得上述免费的KVO通知。)

在我看来,为网点声明属性是过度的。我没有看到它的重点。如果你没有创建属性,nib加载器将通过直接实例变量访问来设置出口,这对于该任务来说很好。

答案 3 :(得分:2)

我认为现代发展已经非常强烈地尝试识别,定义和应用最佳实践。

在这些最佳实践中,我们发现了连续性和一致性。

除了争论在initdealloc方法中使用访问器之外,通常应始终使用访问器(类的内部和外部)来提供它们带来的好处,包括{{3多态var实现(它们都允许抽象和重构)并促进那些连续性和一致性的最佳实践。当以这种方式做事并利用语言能力的充实性时,面向对象语言的基本好处发挥作用。任何高级程序员通常都会证明,在一个人的编码中始终保持一致是一种非常不利的好处。

答案 4 :(得分:0)

你可以这样写

//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