注:这里暂不涉及 @property 定义时的 assign/retain/copy、atomic/nonatomic、readonly/readwrite 属性
环境
Mac OS Yosemite (10.10) + XCode 6.1.1
Pracitce #1
// ========= Person.h =========
@interface Person: NSObject
{
}
-(void) Print;
@property NSString* name;
@end
// ========= Person.m =========
#import "Person.h"
@implementation Person
-(void) Print {
NSLog(@"Print_Name:%@", _name); // #100
}
@end
// ========= main.mm =========
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person* p = [[Person alloc] init];
[p setName:@"Henry"];
NSLog(@"Name:%@", [p name]);
[p Print];
}
}
> Name:Henry
> Print_Name:Henry
说明:
1)@property以及@synthesize等其他directive发挥作用是在预处理阶段,即先按照这些directive的语义将其名下的代码预处理成真正的Objc的代码,比如这里的@property NSString* name会被预处理成真正的类属性“_name”,并为其生成setter/getter方法(name 和 setName)的代码。在这之后,才会真正开始编译。
2)在 #100 处,虽然代码中没有显式定义 _name 的属性,如果是 C++ 代码会报错的,然而这里的 @property name 会在预处理阶段自动生成 _name 属性,因此这里不会报错。
Pracitce #2
// ========= Person.h =========
@interface Person: NSObject
{
@public
NSString* name; // #200
}
-(void) Print;
@property NSString* name;
@end
// ========= Person.m =========
#import "Person.h"
@implementation Person // #201
-(void) Print {
NSLog(@"PrintName:%@", name); // #202
NSLog(@"Print_Name:%@", _name);
}
@end
// ========= main.mm =========
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person* p = [[Person alloc] init];
[p setName:@"Henry"];
NSLog(@"Name:%@", [p name]);
[p Print];
}
}
> Name:Henry
> PrintName:(null)
> Print_Name:Henry
说明:
1) #201 处会出现warning:
Autosynthesized property 'name' will use synthesized instance variable '_name', not existing instance variable 'name'
2) #200 处新加了一个名为 name 的属性,这时会存在两个 name 属性,一个是由 @property NSString* name 自动生成的 _name 属性,另一个是手工添加的 name 属性,前者默认是 private 的,后者被手工指定为 public 的。
3) setter/getter 方法只为 _name 属性提供服务,如果不手工定义 setter/getter 方法的实现,它们会忽略 name 属性,即 #201 处的 warning 所指。
4) 既没有通过 @property 指令定义,又没有手工定义 setter/getter 方法的属性,是不能被类的外部访问到的,即使它是 public 的。
Pracitce #3
// ========= Person.h =========
@interface Person: NSObject
{
@public
NSString* name;
}
-(void) Print;
@property NSString* name;
@end
// ========= Person.m =========
#import "Person.h"
@implementation Person
@syntheize name = _name; // #300
-(void) Print {
NSLog(@"PrintName:%@", name);
NSLog(@"Print_Name:%@", _name);
}
@end
// ========= main.mm =========
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person* p = [[Person alloc] init];
[p setName:@"Henry"];
NSLog(@"Name:%@", [p name]);
[p Print];
}
}
> Name:Henry
> PrintName:(null)
> Print_Name:Henry
说明:
1) #300 处新加了一个名为 name 的属性,这时会存在两个 name 属性,一个是由 @property NSString* name 自动生成的 _name 属性,另一个是手工添加的 name 属性,前者默认是 private 的,后者被手工指定为 public 的。
2) setter/getter 方法只为 _name 属性提供服务,如果不手工定义 setter/getter 方法的实现,它们不会涉及到 name 属性。
3) @synthesize name 和 @synthesize name = _name 等价。
4) 从 Objective-C 2.0 开始,.m 文件中的 @synthesize name 或 @synthesize name = _name 可写可不写。
2) setter/getter 方法只为 _name 属性提供服务,如果不手工定义 setter/getter 方法的实现,它们不会涉及到 name 属性。
3) @synthesize name 和 @synthesize name = _name 等价。
4) 从 Objective-C 2.0 开始,.m 文件中的 @synthesize name 或 @synthesize name = _name 可写可不写。
Pracitce #4
// ========= Person.h =========
@interface Person: NSObject
{
@public
NSString* name; // #400
}
-(void) Print;
@property NSString* name;
@end
// ========= Person.m =========
#import "Person.h"
@implementation Person
@syntheize name = name; // #401
-(void) Print {
NSLog(@"PrintName:%@", name);
NSLog(@"Print_Name:%@", _name); // #402
}
@end
// ========= main.mm =========
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person* p = [[Person alloc] init];
[p setName:@"Henry"];
NSLog(@"Name:%@", [p name]);
[p Print];
}
}
> Name:Henry
> PrintName:(null)
> Print_Name:Henry
说明:
1) #401 处指定了“自动合成的”_name属性实际上将采用 Person.h 中 #400 处手工定义的 NSString* name 属性。
2) #402 处在编译时会报错:Use of undeclared identifier '_name'; did you mean 'name'?
3) 屏蔽 #402 处之后的运行结果:
> Name:Henry
>PrintName:Henry
综述
1) 在
Mac OS Yosemite (10.10) + XCode 6.1.1 的环境下,如果不需要为某个属性自定义 setter/getter 方法的话,在定义这个属性的时候,只需要在 .h 文件中类似 @property NSString* name 这样定义这个属性就可以了,getter/setter 方法会自动生成。
2) 不需要在 @interface 中手工定义该属性变量,也不需要在 .m 文件中再定义 @synthesize name 或 @synthesize name = _name。
3) 注意:这样自动生成的属性的变量名是以下划线开头的,类似 _name。