何时在类属性上使用self?

时间:2009-05-15 04:42:53

标签: objective-c

类属性何时需要?例如:

self.MyProperty = @"hi there";

VS

MyProperty = @"hi there";

MyProperty是一个NSString设置为(非原子,复制)。上述两个内存管理有什么不同吗?

什么时候没有属性,并且在头文件中声明了变量MyProperty?如果从未在类之外引用,是否需要属性?这会对内存管理产生影响吗?

8 个答案:

答案 0 :(得分:8)

是的,内存和性能都有所不同。

MyProperty = @"hi there";

这被认为是直接分配。实际上没有内存或性能影响。当然,这并不是说这是最佳实践 - 这是一个不同的问题:)

@property(nonatomic, copy) NSString *MyProperty;
// ...
self.MyProperty = @"hi there";

此声明对内存和性能有重大影响。这基本上相当于:

-(void)setMyProperty(NSString *)newValue {
    if (MyProperty != newValue) {
        [MyProperty release];
        MyProperty = [newValue copy];
    }
}

释放旧值并将新值复制到MyProperty中。这是可以接受的,尤其是当你的分配字符串是可变的时候处理字符串时(例如,它可能会在以后更改)。

如果在你的例子中,你只是简单地指定一个静态字符串(@“hi there”),直接分配字符串值没有错;它的效率更高,但性能上的差异是微不足道的。

您可以将@property的属性声明为retain,copy或assign(默认为assign)。然后,您可以使用@synthesize生成“访问者”(getter / setter)方法。以下是执行此操作时生成的setter方法的外观:

// @property(nonatomic, assign)
-(void)setMyProperty(NSString *)newValue {
    MyProperty = newValue;
}

// @property(nonatomic, retain)
-(void)setMyProperty(NSString *)newValue {
    if (property != newValue) {
        [property release];
        property = [newValue retain];
    }

// @property(nonatomic, copy)
-(void)setMyProperty(NSString *)newValue {
    if (property != newValue) {
        [property release];
        property = [newValue copy];
    }
}

有关ObjectiveC Declared Properties的更多信息。

“您可以在@implementation块中使用@synthesize和@dynamic指令来触发特定的编译器操作。请注意,任何给定的@property声明都不需要。

重要说明:如果没有为特定属性指定@synthesize或@dynamic,则必须为该属性提供getter和setter(或者只是readonly属性的getter)方法实现。“

换句话说,如果声明属性但不合成属性,除非定义“MyProperty”和“setMyProperty”方法,否则将无法使用[self MyProperty]或self.MyProperty。如果您没有声明属性,那么您只需要一个实例变量。

注意:@dynamic不会生成访问者。如果您通过加载代码或动态方法解析动态地(即,神奇地)解析访问器方法,它就真的被使用了。

答案 1 :(得分:7)

区别在于

self.MyProperty = @"hi there"

是点符号调用,它将调用生成的访问器,它将正确处理保留计数(相当于[self setMyProperty:@“hi there”]),而

MyProperty = @"hi there"

是对您的成员变量的直接赋值,它不会释放旧值,保留新值,或者执行您的访问者所做的任何其他操作(例如,如果您有自定义setter执行额外工作)。

所以,是的,内存管理和两者之间的行为存在很大差异。后一种形式几乎总是错误的,除非您明确知道为什么要这样做,并且您自己正确处理保留计数。

答案 2 :(得分:3)

如果你使用自动Key-Value Observing(或任何基于它构建的Cocoa技术 - 比如绑定,......),使用setter也很重要。如果您分配给ivar,观察员将不会收到任何通知。 如果将“MyProperty”绑定到NSTextfield并通过代码更改“MyProperty”ivar,则绑定的文本字段仍会显示旧值,因为它没有收到任何更改通知。

答案 3 :(得分:2)

访问变量,通常不需要使用点表示法。因此,在XCode模板生成的代码中,您将看到如下内容:

[flipsideViewController viewWillAppear:YES];

这里没有必要编写self.flipsideViewController,因为除了处理变量外,访问器方法通常什么都不做。

所以一个好的经验法则是当你设置一个变量时使用点符号(除非你想要自己保留和释放,否则绝对必要),但是当你是访问:

self.aString = @"Text text text";
NSLog (aString);   // No need for self.aString here
NSString* tmpString = aString; // Here neither

当你使用非对象类型时,比如int或float或许多其他类型,你可以不使用点符号/ setter方法。在这些情况下,没有什么可以保留,所以setter方法除了分配值之外几乎没有什么用。

然而,合成的getter和setter不仅仅是保留和释放。正如其他人所提到的,它们也是保持KVO系统运行的引擎。因此,即使在整数,浮点数和其余部分也应该使用适当的设定器。

那么访问者呢?在更高级的上下文中,即使变量不存在,类也可能响应对变量值的请求。为了引用高级的Objective-C手册,类可以直接或在运行时使用其他机制[而不是简单的访问器方法]提供“方法实现”,例如动态加载代码或动态方法解析。“

(实现这种对消息的即时响应的一种方法是重写NSObject方法,如methodSignatureForSelector:和forwardInvocation:。)

出于这个原因,使用正确声明的接口(无论是否合成)总是一个好主意,当你在做大事。但只要您使用适当的API 设置它们就可以直接访问ivars。

(注意:我不是可可大师,因此非常欢迎更正。)

答案 4 :(得分:1)

对于问题的第二部分,不需要属性定义,这对我们有帮助。属性上的@synthesize指令为属性生成访问器方法,因此我们不必手动执行,因为:

  

此代码指示编译器   生成或合成访问者   方法。编译器将生成   使用的访问方法   经过充分测试的快速算法   准备好多核和   多线程环境,包括   在setter方法中锁定变量。   使用属性不仅减少了   你需要的代码量   写,它用。替换该代码   今天最好的访问者   现代多核系统。以后,如果   你需要提供一个替代方案   财产的实施   访问者,你可以简单地添加   适合您班级的代码。

     

http://developer.apple.com/leopard/overview/objectivec2.html

nonatomic将在访问变量时避免使用锁定,如果您未指定任何内容,则默认值为atomic。锁定在多线程系统上很有用。副本指定应为访问者生成哪些代码,copy将复制对象,retain将保留新对象并释放旧对象,assign对于简单变量(如int)只是普通的分配值。 因此,当您按照(nonatomic,copy)上面的方式定义属性然后使用self.MyProperty = @"Hey"时,您实际上正在调用生成的访问器,它将创建新变量的副本而不是仅仅分配它。您可以覆盖访问者并向其添加检查。

由于上述原因,我会说定义属性即使在类之外没有使用变量也有好处。

我相信您应该使用self.MyProperty而非MyProperty来访问属性,但我无法向您解释原因。 可能与编译器将从

生成的事实有关
self.MyProperty = @"Hey";

这样:

[self setMyProperty: @"Hey"];

但我只是在这里推测。

无论你是调用self.MyProperty还是MyProperty,它都不应该影响内存管理(我仍然更喜欢第一个 - self.MyProperty)。

有关Apple的一些高级别说明,请参阅Objective-C 2.0 Overview

答案 5 :(得分:1)

作为其他答案的补充,尝试以这种方式思考:

self.MyProperty = @"hi there";

[self setMyProperty:@"hi there"];

(相当于)都调用方法,而

MyProperty = @"hi there";

只需设置一个变量。

答案 6 :(得分:1)

这是一个老问题,虽然它曾经是“我什么时候写[self setMyProperty:@"hi there"]?” (请注意,self.MyProperty = @"hi there"与此完全相同。)

我一直听到的答案(而且很有道理)总是使用访问者; 从不MyProperty = @"hi there"。有几个原因:

  1. 为您处理内存管理;你不必担心正确的保留/释放/复制。
  2. 将来修改代码会更容易;如果在某些时候你意识到改变MyProperty需要产生特定的副作用,你可以添加到setter方法,而不是每次都设置MyProperty
  3. 如果您遇到MyProperty问题,可以很容易地将记录代码添加到setter(甚至是getter),以便每次更改(甚至访问)时都能找到它。
  4. 摘要:总是使用[self setMyProperty:@"hi there"]self.MyProperty = @"hi there"从不使用MyProperty = @"hi there",这是最安全和最灵活的。

答案 7 :(得分:0)

还不清楚何时使用访问器以及何时在ivars上进行直接分配?我见过许多直接访问ivars的Apple示例。所以使用所有ivars的属性似乎是迂腐的矫枉过正。

似乎只有重要的ivars需要更长时间并且在外部访问往往使用属性。

希望一些可可大师介入并澄清。