关于Objective-C中的类成员的问题

时间:2011-05-08 18:40:14

标签: objective-c xcode class member

我见过以下定义类成员的风格;但是,我只看到它为对象做了。我很难搞清楚它是否适用于结构(即NSUInteger或enum)和基元(即int,uint,float)。

这是我的aClass.h

typedef enum {
    kValue0 = 0,
    kValue1
} CustomType;

@interface aClass : CCLayerColor {

    NSUInteger _aMember;
    CustomType _anotherMember;
    float _aThirdMember;
    NSString _aFourthMember;

}

@property (assign) NSUInteger aMember;
@property (assign) NSUInteger anotherMember;
@property (assign) NSUInteger aThirdMember;
@property (nonatomic, retain) NSString aFourthMember;

@end

这是我的aClass.m

@implementation aClass

@synthesize aMember = _aMember;
@synthesize anotherMember = _anotherMember;
@synthesize aThirdMember = _aThirdMember;
@synthesize aFourthMember = _aFourthMember;

- (id)init {

    if( (self=[super init] )) {

        NSUInteger _aMember = 100;
        CustomType _anotherMember = kValue0;
        float _aThirdMember = 200.0f;
        NSString _aFourthMember = [[NSString alloc] init];

    }
    return self;
}

在测试中,我发现如果我调用合成的辅助函数(get / set),我可以通过_aMember或aMember同样访问该成员。但我不明白为什么?似乎'@synthesize aMember = _aMember;'只能与对象一起工作,其中aMember和_aMember都指向相同的内存位置。我想我只是不明白这里发生了什么。

有谁能告诉我为什么这样有效?

谢谢, 乔纳森

2 个答案:

答案 0 :(得分:3)

所有@synthesize aMember = _aMember;代码正在为实例变量和属性访问器创建单独的名称。以下面的代码为例:

@interface MyClass {
    NSUInteger _aMember;
}

@property (assign) NSUInteger aMember;

@end


@implementation MyClass
@synthesize aMember = _aMember;

// Above @synthesize statement will create an accessor & mutator similar to this:

- (NSUInteger)aMember {
    return _aMember;
}

- (void)setAMember:(NSUInteger)aMember {
    _aMember = aMember;
}

@end

因此我们创建了一个私有实例变量_aMember和公共属性aMember。在MyClass中,您仍然可以通过调用self.aMember来访问属性并设置实例变量的值。实际上,这与直接设置ivar的行为完全相同(注意这是上面所有的mutator)。另请注意,使用retain语义时(即当您的属性声明为@property (retain) UIView *myView;时),这两个赋值之间的差异会变得很大。使用此方法时,@synthesize生成的mutator也会正确处理保留/释放分配,因此调用self.myView = newView的行为与myView = newView的行为不同。

所以这个符号和id类型的符号相同,因为它是一个简单的ivar重命名,为了惯例。

另外,正如@jer指出的那样,您的代码示例中存在一个问题,即您声明的实例变量的阴影 - 在您的init方法中,您创建的新变量与您的实例变量具有相同的名称。相反,请尝试_aMember = 100;。此外,NSStringid类型,因此您的标头文件中的声明应为NSString *_aFourthMember;@property (nonatomic, retain) NSString *aFourthMember;

希望这有帮助。

编辑:有关使用保留语义的访问者/变更器的更多详细信息。

当我了解这些东西时,我发现知道自动生成的mutator内部发生了什么非常有用。对于声明为@property (nonatomic, retain) UIView *myView;的属性,它是这样的:

- (void)setMyView:(UIView*)newView {
    if (newView != myView) {
        [newView retain];
        [myView release];
        myView = newView;
    }
}

这用于通过使用myView(如果您在拥有类中调用)或self.myView(如果您使用)来为theClass.myView属性分配新对象'从另一个班级打来电话)。如果新分配与现有分配不同,则保留该分配,释放旧值,并将指针分配给myView。

答案 1 :(得分:0)

你有两个基本问题。

  • 遮蔽;和
  • 假设ObjC对象是标量类型。

实际上,您将字符串成员的类型声明为NSString,而不是指向NSString NSString*的指针。所有Objective-C对象都是指向事物的指针。甚至id本身也被声明为指向objc对象的指针。

其次,您通过声明与ivars具有相同名称的局部变量,在init方法中隐藏您的ivars。只需设置你的ivars,不需要将它们声明为局部变量。例如:

_aThirdMember = 200.0f;

将设置ivar,而:

float _aThirdMember = 200.0f;

在堆栈上创建一个float(一个局部变量),当init完成调用时它将消失。不是你想要的。

您还需要阅读properties programming guide,问题的最后部分非常清楚。