调用self.myInstanceVariable和直接调用myInstanceVariable有什么区别?

时间:2009-05-01 16:44:45

标签: iphone objective-c cocoa-touch uikit

这是一个月前我正在读一条关于这一点。我不确定,但我认为如果我调用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 个答案:

答案 0 :(得分:9)

这是正确的。如果您直接使用该变量,绕过getter / setter可能会产生错误。吸气剂/设定器可以负责保留和/或释放物体以及其他物体。这可能导致崩溃/内存泄漏等。

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

答案 1 :(得分:3)

Jesse有一些很好的见解(给你+1,先生)。

我认为直接显式调用底层成员变量(因此绕过getter / setter)的唯一情况是我自己编写了getter / setter,并且确切地知道它是什么而且没有做什么,以及99%的时间是我刚刚在构造函数中初始化成员。

答案 2 :(得分:2)

请阅读文档

首先,这是不正确的

Test* test = [self alloc];

正确

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

其次,如果你写

@synthesize name;

方法

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

将自动生成(!! dot-syntax只是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];
    }
}

所以你不必担心重新发布/释放

答案 3 :(得分:1)

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

另外,作为附注,您可能已经或可能不知道这一点,但如果您打算编写所有的存取方法,那么合成属性是没有意义的。