Objective-C中属性和成员变量到底有什么区别?

1.历史由来

在 iOS5之前,属性的正常写法需要三个步骤

  • 成员变量
  • @property
  • @synthesize

实例代码

@interface ViewController () {
    // 1.声明成员变量
    NSString *name;
}
// 2.用@property
@property(nonatomic, copy)NSString *name;
@end

@implementation ViewController
// 3.最后在@implementation中用synthesize生成set方法
@synthesize name;

如果漏写了 @synthesize,则编译时会有警告

Autosynthesized property 'name' will use synthesized instance variable
 '_name', not existing instance variable 'name'

在iOS5之后,苹果推出一个新机制,@property声明的属性默认会生成一个_类型的成员变量,同时也会生成setter/getter方法。

其实,发生这种状况根本原因是苹果将默认编译器从GCC转换为LLVM(low level virtual machine),才不再需要为属性声明实例变量了。

更换为LLVM之后,编译器在编译过程中发现没有新的实例变量后,就会生成一个下划线开头的实例变量。因此现在我们不必在声明一个实例变量。(注意:是不必要,不是不可以)

在.m文件中,编译器也会自动的生成一个实例变量_name。那么在.m文件中可以直接的使用_name实例变量,也可以通过属性self.name都是一样的。

注意这里的self.myString其实是调用的myString属性的setter/getter方法。这与C++中点的使用是有区别的,C++中的点可以直接访问成员变量(也就是实例变量)。

实战检验

  1. 直接生成成员变量
@interface ViewController () {
    NSString *name;
}
@end

在这段代码里面只是声明了一个成员变量,并没有setter/getter方法。所以访问成员变量时,可以直接访问name,也可以像C++一样用self->name来访问。

// 访问1
name = @"韩雪";
NSLog(@"name = %@",name);

// 访问e2
self->name = @"孙悟空";
NSLog(@"name = %@",self->name);

打印结果
在这里插入图片描述

但绝对不能用self.name来访问

self.name = @"韩雪";

会直接报错
在这里插入图片描述

扩展:很多人觉得OC中的点语法比较奇怪,实际是OC设计人员有意为之。

  • 点表达式(.)看起来与C语言中的结构体访问以及java语言汇总的对象访问有点类似,如果点表达式出现在等号=左边,调用该属性名称的setter方法。如果点表达式出现在=右边,调用该属性名称的getter方法。
  • OC中点表达式(.)其实就是调用对象的setter和getter方法的一种快捷方式,self.myString = @“张三”;实际就是[self setmyString:@“张三”];

首先我们要明白,@synthesize生成了setter/getter方法。

虽然现在直接使用@property时,编译器会自动为你生成以下划线开头的实例变量_myString,不需要自己手动再去写实例变量。而且也不在.m文件中通过@synthesize myString;生成setter/getter方法。但在看老代码的时候,我们依旧可以看到有人使用成员变量+ @synthesize成员变量的形式。

@synthesize还有一个作用,可以指定与属性对应的实例变量,例如@synthesize name = xxx;
那么self.name其实是操作的实例变量xxx,而非_name了。

  • 实例代码1
@synthesize name = myName;

self.name = @"韩雪";
NSLog(@"_name = %@",self->_name);

打印结果
在这里插入图片描述

  • 实例代码2
@synthesize name = myName;

self.name = @"韩雪";
NSLog(@"_myName = %@",self->myName);

打印结果
在这里插入图片描述

2.@dynamic与@synthesize的区别

@dynamic

dynamic告诉编译器,不自动生成getter/setter方法。

  • 实例代码
@interface ViewController ()
@property(nonatomic, copy)NSString *name;
@end

@implementation ViewController

@dynamic name;

- (void)viewDidLoad {
    [super viewDidLoad];

    self.name = @"韩雪";
    NSLog(@"name = %@",self.name);
}
@end

运行结果 - 直接崩溃,报方法找不到的错误。
在这里插入图片描述

@synthesize

添加@synthesize,让编译器自动生成getter/setter方法。
当有自定义的存或取方法时,自定义会屏蔽自动生成的getter/setter方法。

  • 实例代码
@synthesize name = _myName;

- (void)viewDidLoad {
    [super viewDidLoad];

    self.name = @"韩雪";
    NSLog(@"name = %@",self.name);
}

// 自定义 set 方法
- (void)setName:(NSString *)name {
    _myName = @"孙悟空";
}

// 自定义 get方法
- (NSString *)name {
    return _myName;
}

打印结果
在这里插入图片描述

3.总结

成员变量

1. 成员变量的默认修饰是@protected2. 成员变量不会自动生成set和get方法,需要自己手动实现。
3. 成员变量不能用点语法调用,因为没有set和get方法,只能使用->调用。

属性

1. 属性的默认修饰是@protected2. 属性会自动生成set和get方法。
3. 属性用点语法调用,点语法实际上调用的是set和get方法。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值