基本的Objective-C变量声明

5
我对Objective C中变量的声明方式感到困惑。
1: 我看到使用了@property和@synthesize语句。我的问题是,这两个语句是做什么用的?为什么它们总是一起使用?我猜测@synthesize是一个快捷方式来创建getter和setter?
2: 假设我想声明一个NSMutableArray,该数组只能在声明它的类内部访问。在使用addObject方法写入内容之前,我必须执行myArray = [[NSMutableArray alloc] init]。那么我什么时候释放数组呢?
3: 在只有在声明它的类内部才能访问的变量被声明后,还有没有其他不同的方法使之被所有类访问?
4: 类似于问题2,但现在变量是NSString。为什么我不需要分配和初始化它就可以在其所属的类中共享相同的变量?self.myString = @"";与myString = @"";之间有什么区别吗?
非常感谢。

当你开始学习Objective-C时,你可能会想要参考一下斯坦福大学的课程(iTunes)。这对我帮助很大,让我更快地掌握了学习曲线。 - nykash
这是一个非常广泛的问题,涉及到在SO上已经被广泛讨论的领域。请先四处看看。以下是四篇以前的文章,涵盖了您的问题。1:@property和@synthesize之间有什么区别?2:何时释放实例变量?3:如何声明不在实例外可见的实例变量?4:self.var与var之间的区别。每个主题都有其他文章。 - jscs
4个回答

5

针对您的第一个问题:

@property (nonatomic, retain) NSString * someProperty;

这声明了一个类的属性。它成为了类的公共合约的一部分,但仍然缺少重要的东西 - 实际的实现

@synthesize someProperty;

这是编译器语法糖,它为您的属性创建一个getter和setter方法。也就是说,这是在类中实际使用属性以及从其他类中使用属性所需的实现。
几乎在所有情况下,您都需要为您声明的每个@property都有一个@synthesize。
对于您的第二个问题:
您关于如何初始化数组属性是正确的。为了释放它,您可以在类的dealloc方法中执行以下操作:
- (void) dealloc {
    self.myarray = nil;

    [super dealloc];
}

假设你使用retain关键字声明了属性,这将有效地释放数组。


至于你最后一个问题:

类的属性始终可以从其他类访问。为了创建一个全局可访问的变量,你需要将其声明为static


你可能不需要为每个属性都使用@synthesize。它也可以是@dynamic,或者你可以简单地声明一个ivar并实现正确命名的方法。 - jscs
我同意你的第一个观点,但是你的第二个观点与@property无关,更多地与KVC有关。我编辑了我的答案以反映这一点。 - Perception
1
@Josh:确实。在其他评论中,我给出了一些例子,你可以编写自己的访问器,甚至没有实例变量,因为访问器可以依赖于其他方式(直接文件访问、端口、数据库、算法等)来直接获取或设置实例变量。在这种情况下,你不需要合成。 - Rudy Velthuis
@Perception:对于属性来说,第二点也很重要,因为编译器默认将 self.ivar = obj; 翻译成 [self setIvar:obj];,将 [obj doSomething:self.ivar]; 翻译成 [obj doSomething:[self ivar]]。当然,你可以告诉编译器使用其他方法名:@property (getter=bananas, setter=setRutabegas, copy) NSString * apples;,但是你仍然必须按照你在声明属性时承诺的方式命名这些方法。 - jscs
如果您创建的方法与编译器合成的方法同名,则没有问题。但是,除非您确切地知道为什么要避免使用 @synthesize,否则不建议采用这种方法。 - Perception

2

广告1:属性是一种构造,用于通过getter和setter控制访问ivar(通常是私有的)。实际上,属性甚至不必具有支持ivar。是的,@synthesize会生成getter和setter(以及ivar)。

广告2:当你不再需要它时,你可以释放它。这取决于你的代码逻辑。

广告3:如果我理解正确,你想要@private ivars。通常,ivar是受保护的,即只能在类内或派生类中访问。私有ivar仅在类本身内部可访问。属性是公开可访问的。

广告4:myString = @""直接写入ivar,而self.myString = @""使用属性setter。


我曾经遇到这样一种情况,即在类内部无法读取ivar。当时我使用的是ivar = something,但将其更改为self.ivar = something后问题得以解决。您能否分享一些关于发生了什么的见解?我猜测ivar被自动释放了,因为我读取了NULL。如果有帮助的话,该ivar是CLLocation。对于NSString ivars,我不需要执���self - John
属性如果声明为(copy)或(retain),将保留该项(并释放先前的项),而直接访问ivar不会做任何操作。属性可以帮助您执行内存管理,因为编译器将生成正确保留和释放项的代码。当然,它们仍然必须在dealloc中释放。因此,请尝试在各处使用属性,除了init和dealloc可能例外。 - Rudy Velthuis

0
你需要获取一份Objective-C的文本或者找到一个在线教程。这是一种足够深奥的语言,你不能指望零零散散地学会它。
有变量和属性两种东西,它们有些交叉但又不完全相同。
你可以像在C/C++中一样声明普通的实例变量,差不多就是这个样子:
NSArray* myArray;

例如,放置在 @interface 的 {} 包含部分中。

但是您还可以拥有一个属性,通过在 @interface 声明中使用 @property 来声明(在关闭 } 后)。属性具有 getter 方法 - 默认情况下称为 myProperty - 和 putter 方法 - 默认情况下称为 setMyProperty。如果 myProperty 与您的实例变量之一同名,则可以使用 @synthesize 自动创建这些方法。

请注意,当使用默认 setter 方法时,属性可能会自动保留。从管理存储的角度来看,这相当方便。

但是,管理存储是一个大主题,您必须阅读一些好的教程 - 我们无法在几段中解释清楚。


0

1) @property声明一个公共可访问的变量和相关的getter和setter。 @synthesize会导致编译器自动生成getter和setter的定义(代码)。

2) 您将在类声明中,在头文件中声明NSMutableArray。您将在init方法中初始化变量,并在dealloc方法中释放变量。

3) 使用@property创建的变量是公共的。使用类声明中定义的变量(在头文件中使用@interface)可以使用@private关键字声明为该类的私有变量。

John,这些问题非常基础。您可能会从这里的Objective-C编程介绍中获得很多信息(http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Introduction/introObjectiveC.html#//apple_ref/doc/uid/TP30001163)。


@property不声明一个公开可访问的变量。ivar本身(如果被合成)是@protected的。它声明的是类某些方面的访问点。实际上,甚至不需要有支持它的变量,只要满足具有getter和setter方法(或仅具有getter,在readonly的情况下)的合约即可。 - jscs
1
如果你自己编写getter和/或setter,一个属性甚至不需要有ivar。它同样可以计算一些东西,或者将一个项目转换为另一个项目。例如,一个角度类可以像一个弧度属性一样拥有一个度数属性。只有弧度属性有一个支持ivar,但是度数属性(通过setter和getter,分别为degreessetDegrees:)根据方向转换为弧度或度数。一个文件类可以有一个fullName属性,它使用服务器、目录和文件名来生成或解析完全限定名称。 - Rudy Velthuis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接