【Objective-C】浅析OC中的属性关键字

重新学习一下OC中的属性关键字,重点复习深浅拷贝。
属性关键字默认为

@property(assign, nonatomic, readwrite)NSInteger number;

@property、@synthesize和@dynamic

  • @property
    属性用于封装对象中的数据,其本质是实例变量+setter+getter
    可以用@property语法声明属性,ta会帮我们自动生成属性的setter/getter方法的声明
  • @synthesize
    帮我们自动生成属性的setter/getter方法的实现
    现在的Xcode版本已经不需要此关键字来帮助合成getter/setter方法
    我们仍可以通过@synthesize来指定实例变量的名字,也就是说可以更改默认的以下划线开头来命名的实例变量的名字,根据自己的个人习惯,在不影响可读性的前提下。

如果不想令编译器合成存取方法,则可以自己实现。如果你只实现了其中一个存取方法 setter or getter,那么另一个还是会由编译器来合成。但是需要注意的是,如果你实现了属性所需的全部方法(如果属性是 readwrite 则需实现 setter and getter,如果是 readonly 则只需实现 getter 方法),那么编译器就不会自动进行 @synthesize,这时候就不会生成该属性的实例变量,需要根据实际情况自己手动 @synthesize 一下

@synthesize instanceVariable = _instanceVariable;
  • @dynamic
    告诉编译器不用自动进行 @synthesize,你会在运行时再提供这些方法的实现,无需产生警告,但是它不会影响 @property 生成的 setter 和 getter 方法的声明。@dynamic 是 OC 为动态运行时语言的体现。动态运行时语言与编译时语言的区别:动态运行时语言将函数决议推迟到运行时,编译时语言在编译器进行函数决议。
@dynamic ivar;

以前我们需要手动对每个 @property 添加 @synthesize,而在 iOS 6 之后 LLVM 编译器引入了 property autosynthesis,即属性自动合成。换句话说,就是编译器会自动为每个 @property 添加 @synthesize。
那你可能就会问了,@synthesize 现在有什么用呢?

  1. 如果我们同时重写了 setter 和 getter 方法,则编译器就不会自动为这个 @property 添加 @synthesize,这时候就不存在 _ivar,所以我们需要手动添加 @synthesize
  2. 如果该属性是 readonly,那么只要你重写了 getter 方法,property autosynthesis 就不会执行,同样的你需要手动添加 @synthesize 如果你需要的话,看你这个属性是要定义为存储属性还是计算属性吧
  3. 实现协议中要求的属性

此外需要注意的是,分类当中添加的属性,也不会 property autosynthesis 。因为类的内存布局在编译的时候会确定,但是分类是在运行时才加载并将数据合并到宿主类中的,所以分类当中不能添加成员变量,只能通过关联对象间接实现分类有成员变量的效果。如果你给分类添加了一个属性,但没有手动给它实现 getter、setter(如果属性是 readonly 则不需要实现)的话,编译器就会给你警告 Property 'ivar' requires method 'ivar'、'setIvar:' to be defined - use @dynamic or provide a method implementation in this category,编译器已经告诉我们了有两种解决方式来消除警告:

  1. 在这个分类当中提供该属性 getter、setter 方法的实现
  2. 使用 @dynamic 告诉编译器 getter、setter 方法的实现在运行时自然会有,您就不用操心了。当然在这里 @dynamic 只是消除了警告而已,如果你没有在运行时动态添加方法实现的话,那么调用该属性的存取方法还是会 Crash。

属性关键字分类

分类属性关键字
原子性atomic、nonatomic
读写权限readwrite、readonly
方法名setter、getter
内存管理assign、weak、unsafe_unretained、retained、strong、copy
类属性class

原子性

  • atomic

原子性(默认),编译器会自动生成互斥锁(以前是自旋锁,后面改为了互斥锁),对 setter 和 getter 方法进行加锁,可以保证属性的赋值和取值的原子性操作是线程安全的,防止出现数据竞争或不一致的结果,但不包括操作和访问(原子性)。

比如说 atomic 修饰的是一个数组的话,那么我们对数组进行赋值和取值是可以保证线程安全的。但是如果我们对数组进行操作,比如说给数组添加对象或者移除对象,是不在 atomic 的负责范围之内的,所以给被 atomic 修饰的数组添加对象或者移除对象是没办法保证线程安全的

  • nonatomic

非原子性,一般都用此修饰符来修饰属性,使用 nonatomic 修饰属性时,访问器(getter)和设置器(setter)方法不会加锁,不提供原子性保证。这意味着在多线程环境下,可能出现数据竞争的情况。相比于 atomic,nonatomic 的访问速度更快,因为不需要加锁操作

读写权限

  • readwrite

读写(默认),同时生成setter和getter方法的声明和实现

  • readonly

只读,即指生成getter方法的声明和实现(体现封装特点,必要时才将属性暴露出来)

方法名

  • setter

用于指定生成的setter方法名

  • getter

用于指定生成的getter方法名

使用示例如下(假设该属性在一个名为Student类的类中声明)

@property(copy, nonatomic, setter=gNAME:, getter=gNAME) NSString* girlFriendName;
Student* s = [[Student alloc] init];
[s gNAME: @"JZ"];
NSLog(@"%@", [s gNAME]);

也就是给自动生成的getter/setter方法换了个名字

内存管理

  • assign
  1. setter方法的实现是直接赋值,一般用于修饰基本数据类型(NSInteger、BOOL、int、float等)
  2. 修饰对象类型时,不增加其引用计数
  3. 会产生悬垂指针(悬垂指针:悬垂指针:assign 修饰的对象在被释放之后,指针仍然指向原对象地址,该指针变为悬垂指针。这时候如果继续通过该指针访问原对象的话,就可能导致程序崩溃
  • weak
  1. 仅修饰对象类型
  2. ARC下才能使用
  3. 修饰弱引用,不增加对象引用计数,主要用于避免循环引用(强引用循环)
  4. weak 修饰的对象在被释放之后,会自动将指针置为 nil,不会产生悬垂指针
  5. 对于视图,通常还是用在 xib 和 storyboard 上;代码中对于有必要进行 remove 的视图也可以使用 weak,这样 remove 之后会自动置为 nil
  • unsafe_unretained
  1. 一般在MRC下使用
  2. 与weak的区别就在于unsafe_unretained就产生悬垂指针
  3. weak 对性能会有一定的消耗,当一个对象 dealloc 时,需要遍历对象的 weak 表,把表里的所有 weak 指针变量值置为 nil,指向对象的 weak 指针越多,性能消耗就越多。所以 unsafe_unretained 比 weak 快。当明确知道对象的生命周期时,选择 unsafe_unretained 会有一些性能提升
    比如 A 持有 B 对象,当 A 销毁时 B 也销毁。当 B 存在,A 就一定会存在。而 B 又要调用 A 的接口时,B 就可以存储 A 的 unsafe_unretained 指针。虽然这种性能上的提升是很微小的。但当你很清楚这种情况下,unsafe_unretained 也是安全的,自然可以快一点就是一点。而当情况不确定的时候,应该优先选用 weak
  • retain
  1. 一般在ARC下使用
  2. 修饰强引用,将指针原来指向的旧对象释放掉,然后指向新对象,同时将新对象的引用计数加1
  3. setter方法实现的是release旧值,retain新值,用于OC对象类型
  • strong
  1. ARC下才能使用
  2. 类似retain
  3. 但在修饰block时,strong相当于copy,而retain相当于assign
  • copy
  1. setter 方法的实现是 release 旧值,copy 新值,一般用于修饰 block、NSString、NSArray、NSDictionary 等类型
  2. 使用 copy 或strong 修饰 block 其实都一样,用 copy 是为了和 MRC 下保持一致的写法
  3. 修饰 NSString、NSArray、NSDictionary 是为了保证赋值后是一个不可变对象,以免遭外部修改而导致不可预期的结果

类属性class(简单了解)

Objective-C类属性是在 Xcode 8 支持的,为了与 Swift 类型属性互操作,它不会进行 property autosynthesize。可以说自从 Swift 发布了后,Objective-C 的更新几乎都是为了更好地与 Swift 混编写

属性可分为示例属性和类属性:

  • 实例属性:每个实例都有一套属于自己的属性值,他们之间时相互独立的
  • 类属性:可以为类本身定义属性,无论创建了多少个该类型的实例,这些属性都只有唯一一份,因为类时单例。

用处:类属性用于定义某个类型所有实例共享的数据,比如所有实例都能用的一个常量/变量(类似于C语言中的静态常量/静态变量)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值