IOS属性代码分析

目录

一、IOS属性修饰符

二、属性修饰符分析

(一)、copy

(二)、assign

(三)、retain

(四)、strong

(五)、weak

(六)、readwrite

(七)、readonly

(八)、nonatomic/atomic


本文章为作者的学习总结文档,如有转载,侵权,请联系作者

一、IOS属性修饰符

主要的属性属性修饰符有以下几种:

  • copy
  • assign
  • retain
  • strong
  • weak
  • readwrite/readonly(读写策略,访问权限)
  • nonatomic/atomic(安全策略)

如果按照MRC和ARC进行区分修饰符的使用情况,可以按如下方式进行分组:

1.MRC: assign/ retain/ copy/ readwrite、readonly/ nonatomic、atomic 等。
2.ARC: assign/ strong/ weak/ copy/ readwrite、readonly/ nonatomic、atomic 等。

属性修饰符对retainCount计数的影响:

1.alloc为对象分配内存,retainCount为1。

2.retain MRC下 retainCount +1。

3.copy一个对象变成新的对象,retainCount为1,原有的对象计数不变。

4.release对象的引用计数-1。

5.autorelease对象的引用计数retainCount -1,如果为0,等到最近一个pool结束时释放。

二、属性修饰符分析

(一)、copy

使用场景

1.一般情况下,copy可以用于对不可变变量的属性修饰中,主要是NSArray/NSDictionary/NSString,也可以用来修饰block。

2.在MRC和ARC下都可以使用。

应用举例

@property (nonatomic, copy, nullable) SDWebImageTransitionPreparesBlock prepares;
@property (nonatomic, copy) NSString *imageKey;
@property (nonatomic, copy) NSArray *frames;

问题:

a.block为什么要用copy修饰?

因为block在创建的时候,他的内存是分配在栈上的,而不是堆上。栈中的block的生命周期是和栈绑定的。他本身的作用域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。为了能够在block的声明域外使用,所以只有使用copy后,block才会在堆中。并且block的retain行为默认是用copy的行为实现的。

b.为什么大部分要用nonatomic修饰?

为了使nonatomic修饰的属性访问速度更快。

c.nullable是什么属性修饰符

nullable表示修饰的属性或参数可以为空。

d.NSString为什么是用的是copy而不是strong?

当我们十分确定,要给属性NSString赋一个不可变的值是,用strong。如果用copy来修饰属性,在进行赋值的时候,会先做有个类型判断,如果赋的值是一个不可变的字符串,则走strong的策略,进行浅拷贝;如果是可变的字符串,就进行深拷贝创建一个新的对象。

如果我们确定是个属性赋值一个不可变的值,那么就用strong。但是很多情况下我们并不确定要赋的值是什么类型,所以我们一般还是用copy来修饰。这样保证了安全性。因为如果赋值的可变字符串,当他发生变化时,用strong修饰的属性的值也是会跟着变化的;而用copy修饰的属性,因为是深拷贝所有不会发生变化。

e.NSArray为什么是用的是copy而不是strong?

因为如果使用strong声明一个NSArray属性,那么这个属性有可能指向一个可变对象,并且可能该属性会在不知情的情况下被人修改。因此最好拷贝一份不可变的数据,确保不会意外的被修改。所以NSArray会使用copy修饰。

(二)、assign

使用场景

1.在MRC和ARC下都可以使用。

2.用于非指针变量。一般用来修饰基础数据类型(NSInteger,CGFloat)和C数据类型(int,float,double)等。他的setter方法直接赋值,不进行任何retain操作。

应用举例

@property (nonatomic, assign) BOOL hasInitialBoundary;
@property (nonatomic, assign) unsigned long long bodyContentLength;

问题:

a.为什么assign一般修饰的都是基础数据类型?

因为使用assign修饰时,如果对象被销毁时并不会将指针置为nil。所以当对空间的对象销毁时指向对象的指针仍然存在,会造成野指针,当访问该对象时会crash报错EXC_BAD_ACCESS。而修饰基础数据类型,基础数据类型的空间开辟也是在栈空间,由系统进行自动销毁,所以不会造成野指针出现的情况。

b.为什么id要用assign修饰而不是retain?

因为如果使用retain可能会造成循环引用的问题,使用assign,不会使引用计数 +1,避免了出现循环引用的情况。

(三)、retain

使用场景

1.一般情况下,retain用在MRC情况下,被retain修饰的对象,引用计数retainCount +1。

2.retain只能修饰OC对象,不能修饰非OC对象,比如说Core Foundation对象就是C语言框架,他没有引用计数,也不能用retain进行修饰。

3.retain一般用来修饰非NSString的NSObject类和其子类。

4.用于指针变量。就是说你定义了一个变量,然后这个变量在程序的运行过程中会被更改,并且影响到其他方法。一般是用于字符串( NSString,NSMutableString),数组(NSMutableArray,NSArray),字典对象,视图对象(UIView ),控制器对象(UIViewController)等。

应用举例

/// 右侧按钮
@property (nonatomic, retain) NSArray *rightBarItems;
/// 左侧按钮
@property (nonatomic, retain) NSArray *leftBarItems;
@property (nonatomic, readwrite, retain) UIView *inputAccessoryView;

问题:

a.MRC下assign和retain的区别?

assign只是简单的赋值操作,他引用的对象被释放,不会赋值为nil,有可能会造成野指针,可能会出现crash情况;retain会使对象的retainCount计数 +1,获得对象的拥有权,只有对象的引用计数为0的时候才会被释放,避免访问一个被释放的对象。

(四)、strong

使用场景

1.strong表示对对象的强引用,对象的引用计数retainCount +1.

2.ARC下也可以用来修饰block,strong和weak两个修饰符默认是strong。

3.修饰控件可以用strong。

应用举例

@property (readwrite, nonatomic, strong) NSMutableArray *HTTPBodyParts;
@property (nonatomic, strong) UIImage *image;

问题:

a.为什么NSMutableArray用strong而不是copy? 例如:

@property (nonatomic, copy) NSMutableArray *mArray;//等同于
- (void)setMArray:(NSMutableArray *)mArray {
_mArray = mArray.copy;
}

mArray属性就成了NSArray,NSMutableArray只能用strong修饰,不存在有copy修饰的情况,写了就成了NSArray。如果是strong,直接是赋值_mArray = mArray;右边是什么,左边就是什么,并且是强引用新值。 所以用copy关键字的话,调用setter方法后。是对赋值对象进行深拷贝。并且拷贝的对象是copy的(不可变的)不是mutableCopy的(可变的)。所以用copy修饰的mutableArray也被视为Array了,所以再用mutableArray的方法就会发生崩溃。

(五)、weak

使用场景

1.weak表示对对象的弱引用,被weak修饰的对象随时可被系统销毁和回收。

2.weak比较常用的地方就是delegate属性的设置。

3.用weak修饰弱引用,不会使传入对象的引用计数 +1。

应用举例:

@property (nonatomic, weak) id delegate;

问题:

a.修饰代理用weak还是assign?

assign是指针引用,不对引用计数操作,使用之后如果没有置为nil,就会变成野指针,所以如果用assign修饰。delegate指向的对象被销毁了,delegate中依然会保存之前对象的地址,delegate就变成了野指针。

而对于weak,delegate这个对象的销毁由外部控制。当delegate指向的对象销毁后,delegate = nil。

所以修饰delegate要用weak。

b.修饰代理为什么不用strong?

因为如果用strong修饰对象会对该对象进行强引用,外界不能销毁该对象,这样会导致循环引用。所以使用weak,weak不会引用计数 +1,这样可以避免循环引用。

(六)、readwrite

使用场景

1.用readwrite修饰的时候表示该属性可读可写。

2.readwrite程序自动创建setter/getter方法。

3.系统默认的情况是readwrite。

应用举例

@property (readwrite, nonatomic, strong) id field;
@property (readwrite, nonatomic, strong) id value;

(七)、readonly

使用场景

1.用readonly修饰表示这个属性只可读,不可修改,一般常用在我们不允许外界改变只允许外界读取。

2.readonly程序创建getter方法。

应用举例

@property (readonly, nonatomic, assign) unsigned long long contentLength;
@property (readonly, nonatomic, assign, getter = isEmpty) BOOL empty;

(八)、nonatomic/atomic

使用场景

1.nonatomic非原子属性。他的特点是多线程并发性访问性能高,但是访问不安全。

atomic原子属性(atomic是通过锁定机制来确保其操作的原子性)。他的特点是安全但是是以耗费系统资源为代价,所以一般工程用nonatomic的时候比较多。

2.系统默认的是atomic,为setter方法加锁,而nonatomic不为setter方法加锁。

应用举例

@property (nonatomic, copy) NSString *boundary;
@property (nonatomic, strong) id body;
@property (nonatomic, assign) unsigned long long bodyContentLength;

问题:

a.多线程下加atomic就是安全吗?

这个说法是不正确的。atomic的安全只是在getter和setter方法的时候是原子操作,是安全的。但是其他方面是不在atomic管理范围之内的,这个时候不能保证安全。

你可能感兴趣的:(ios,objective-c)