我见过以下定义类成员的风格;但是,我只看到它为对象做了。我很难搞清楚它是否适用于结构(即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都指向相同的内存位置。我想我只是不明白这里发生了什么。
有谁能告诉我为什么这样有效?
谢谢, 乔纳森
答案 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;
。此外,NSString
是id
类型,因此您的标头文件中的声明应为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)
你有两个基本问题。
实际上,您将字符串成员的类型声明为NSString
,而不是指向NSString NSString*
的指针。所有Objective-C对象都是指向事物的指针。甚至id
本身也被声明为指向objc对象的指针。
其次,您通过声明与ivars具有相同名称的局部变量,在init方法中隐藏您的ivars。只需设置你的ivars,不需要将它们声明为局部变量。例如:
_aThirdMember = 200.0f;
将设置ivar,而:
float _aThirdMember = 200.0f;
在堆栈上创建一个float
(一个局部变量),当init完成调用时它将消失。不是你想要的。
您还需要阅读properties programming guide,问题的最后部分非常清楚。