2

一个月前,我正在读一篇关于此的文章。我不确定,但我认为如果我调用 self.myInstanceVariable 那么它会自动使用 getter/setter,但是如果我直接调用 myInstanceVariable = @"Foo" 例如,那么我会绕过任何真正的 getter/setter ,真的,非常糟糕。正确错误?

编辑:我在 XCode 中试过这个。

实现如下所示:

@implementation Test
@synthesize name;

+ (Test*)testWithName:(NSString*)name {
    Test* test = [self alloc];
    test.name = name;
    return [test autorelease];
}

- (void)setName:(NSString*)newName {
    NSLog(@"SETTER CALLED!!");
    if(name != newName) {
        [name release];
        name = [newName retain];
    }
}

- (NSString*)name {
    NSLog(@"GETTER CALLED!!");
    return name;
}

- (void)doWrongThing {
    NSString *x = name;
    NSLog(@"doWrongThing: %@", x);
}
- (void)doRightThing {
    NSString *x = self.name;
    NSLog(@"doRightThing: %@", x);
}

测试代码如下所示:

Test *t = [Test testWithName:@"Swanzus Longus"];
//NSLog(@"%@", t.name);
[t doWrongThing];
[t doWrongThing];
[t doWrongThing];

[t doRightThing];

因此,在以另一种方法启动此代码后(我只是使用了现有项目;)),我在控制台中收到了以下输出:

2009-05-01 19:00:13.435 Demo[5909:20b] SETTER CALLED!!
2009-05-01 20:19:37.948 Demo[6167:20b] doWrongThing: Swanzus Longus
2009-05-01 20:19:37.949 Demo[6167:20b] doWrongThing: Swanzus Longus
2009-05-01 20:19:37.949 Demo[6167:20b] doWrongThing: Swanzus Longus
2009-05-01 20:19:37.950 Demo[6167:20b] GETTER CALLED!!
2009-05-01 20:19:37.965 Demo[6167:20b] doRightThing: Swanzus Longus

如您所见,您必须使用 self.instanceVariableName 才能使用 getter 和 setter(或者您在括号中进行调用,也可以)。

混淆警报:只有在您想要访问实例变量的对象的方法中进行修改时,您才必须使用 self 。从外部看,当您调用 someObjectPointer.someInstanceVariable 时,它​​会自动访问 getter 和 setter(是的,我也尝试过)。

只是以为有人会对一个小案例研究感兴趣;)

4

4 回答 4

9

那是对的。如果您直接使用该变量,绕过 getter/setter,您可能会产生错误。getter/setter 可能负责保留和/或释放对象以及其他事情。这可能会导致崩溃/内存泄漏等。

如果您知道自己绕过了 getter/setter 并采取了正确的预防措施,那么直接访问变量就没有错。

于 2009-05-01T16:49:40.683 回答
3

杰西有一些很好的洞察力(+1 给你,先生)。

我会考虑直接显式调用底层成员变量(从而绕过 getter/setter)的唯一情况是我自己编写了 getter/setter,并且确切地知道它在做什么和不做什么,并且 99%那些时候是我刚刚在构造函数中初始化成员的时候。

于 2009-05-01T17:03:18.420 回答
2

只需阅读文档

首先,这是不正确的

Test* test = [self alloc];

正确的是

Test* test = [[self alloc] init];

第二,如果你写

@synthesize name;

方法

- (void)setName:(NSString*)newName
- (NSString*)name

将自动生成(!! dot-syntax is just syntax-sugar !!)

三、写的时候

myvar.itInstanceVariable

它转化为

[myvar itInstanceVariable]

myvar.itInstanceVariable = newValue

翻译成

[myvar setItInstanceVariable:newValue]

关于您的评论,当您以这种方式声明您的财产时

@property(nonatomic, retain) MyType *myVar;

并写在实现中

@synthesize myVar

它创建了两种方法

- (MyType*)myVar {
     return myVar;
}

- (void)setMyVar:(MyType*)newVar {
    if (myVar != newVar) {
       [myVar release];
       myVar = [newVar retain];
    }
}

所以你不必担心重新租借/释放

于 2009-05-02T16:46:48.500 回答
1

是的,属性语法调用 setter。在几乎所有情况下,这都是您想要的,因为默认情况下它会正确处理大量内存管理。此外,属性名称、ivar 名称和 getter/setter 名称也可能不同,因此您可能会发现它看起来不像self.myInstanceVar.

另外,作为旁注,您可能已经知道也可能不知道,但是如果您只是要编写所有访问器方法,那么综合属性是没有意义的。

于 2009-05-01T18:49:00.290 回答