在一个开发交流群里,看到这么一个问题:重写setter和getter时候报错:Use of undeclared identifier '_name'; did you mean 'name'?
。
应该是这样的:
然后有人说:”撸了4年的代码,竟然不知道@property声明的变量不能同时重写getter和setter“
有么有很惊讶。
然后我在群里说,可以写getter和setter的,并附上一行代码:
@synthesize name = _name;
有些细节,想清楚了,可能更容易理解这们语言。
声明成员变量
@interface Person : NSObject
{
NSString *_name; //注意下划线是我们手动添加的
}
@end
OC语言在{}直接声明成员变量,形式如下:
{
变量类型 *变量名
}
声明变量后在类的外部是不能访问的。访问一个变量我们一般使用"."语法,或者[],即”点语法“和方括号。
点语法的实质是访问getter和setter。
所以我们需要给变量实现get和set方法,以便类使用该变量。
@interface Person : NSObject
{
NSString *_name;
}
- (void)setName:(NSString *)name;
- (NSString *)name;
@end
并实现setter和getter
@implementation Person
- (void)setName:(NSString *)name {
_name = name;
}
- (NSString *)name {
return _name;
}
@end
由于我们写的setter和getter是写给name的,并非是_name,所以外部访问的时候是model.name,而不是model._name。
getter方法拿到的值,确是_name这个变量的值,外部通过set方法给name赋值,也是赋值给了变量_name。
OC中声明一个属性使用@property关键字:
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@end
用@property声明一个属性,系统会自动生成一个名字为_属性的成员变量,即生成_name。并且系统会自动生该成员变量的setter和getter方法。
总而言之就是用@property声明一个属性 = 声明一个成员变量 + 自动生成成员变量的存取方法(setter+getter)。
属性不是变量,对象类型的属性其实是声明了一个指针,这个指针的地址指向的是变量_name。@property声明的基础的属性是一个变量。
我们在访问属性name的时候,实际上是访问的_name,只不过是通过指针name访问的。
该关键字是OC用来生成属性的关键字。
使用@property声明一个属性后,为什么重写写setter和getter会报错?
声明
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@end
重写setter和getter
- (void)setName:(NSString *)name {
_name = name;
}
- (NSString *)name {
return _name;
}
报错是必然的,不报错那就奇怪了。
报错的原因是系统无法识别_name,就报出错误:undeclared identifier '_name’相关的错误信息。
为什么我们写setter和getter的时要用_name呢?通过_name能直接取到变量_name的内容吗?
_name是系统生成的一个成员变量,成员变量在外部是不能直接被访问的,需要用getter和setter方法来访问。所以会报错。
重写属性的setter和getter方法,无法对应到默认的成员变量_name,需要手动定义一个变量或者使用@synthesize指定一个变量来绑定到该属性上。
要解决@property中提到的问题,有两种办法:
使用@synthesize声明一个变量,绑定到属性上。
@synthesize name = _name;
这里可以直接使用_name,也可以使用别的变量,比如_lastName
@synthesize name = _lastName;
第一种是直接将系统生成的变量_name和属性name做了对应关系;第二种是声明了一个新的变量_lastName和name做了对应关系。建议直接使用_name,不再声明新的变量。
@implementation Person
@synthesize name = _name;
- (void)setName:(NSString *)name {
_name = name;
}
- (NSString *)name {
return _name;
}
@end
定义变量
@interface Person : NSObject
{
NSString *_name;
}
@property (nonatomic, strong) NSString *name;
@end
绑定属性
@implementation Person
- (void)setName:(NSString *)name {
_name = name;
}
- (NSString *)name {
return _name;
}
@end