OC关于重写属性的setter和getter的问题

文章目录

  • OC关于重写属性的setter和getter的问题
    • 一、背景
    • 二、成员变量、@property、属性、@synthesize。
      • 成员变量
      • 属性
      • @property
      • @synthesize
        • 1、使用@synthesize
        • 2、定义新变量
    • 总结

OC关于重写属性的setter和getter的问题

一、背景

在一个开发交流群里,看到这么一个问题:重写setter和getter时候报错:Use of undeclared identifier '_name'; did you mean 'name'?

应该是这样的:

OC关于重写属性的setter和getter的问题_第1张图片

然后有人说:”撸了4年的代码,竟然不知道@property声明的变量不能同时重写getter和setter“

有么有很惊讶。

然后我在群里说,可以写getter和setter的,并附上一行代码:

@synthesize name = _name;

有些细节,想清楚了,可能更容易理解这们语言。

二、成员变量、@property、属性、@synthesize。

成员变量

声明成员变量

@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访问的。

@property

该关键字是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方法来访问。所以会报错。

@synthesize

重写属性的setter和getter方法,无法对应到默认的成员变量_name,需要手动定义一个变量或者使用@synthesize指定一个变量来绑定到该属性上。

要解决@property中提到的问题,有两种办法:

1、使用@synthesize

使用@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

2、定义新变量

定义变量

@interface Person : NSObject
{
    NSString *_name;
}
@property (nonatomic, strong) NSString *name;

@end

绑定属性

@implementation Person

- (void)setName:(NSString *)name {
    _name = name;
}
- (NSString *)name {
    return _name;
}

@end

总结

  • 属性是一个指针,并非一个变量
  • 使用@property声明一个属性,实际上是声明了一个指针+对应的变量+该变量的存取方法
  • 访问属性的”值“,本质上是获取、该属性对应的成员变量的内容
  • @synthesize可以指定指针和变量的对应关系

你可能感兴趣的:(#,Foundation)