OC语言-属性关键字

2019-07-12  本文已影响0人  亲爱的大倩倩
属性关键字分类
#属性关键字可以分为三类#
//带星标的为默认
1.读写权限: *readwrite  readonly  
2.原子性:   *atomic    nonatomic
3.引用计数
*strong(ARC) / return(MRC)  #这两个关键字都是用来修饰对象
*assign / unsafe_unretained(MRC)  #assign既可以修饰基本数据类型,也可以修饰对象类型
weak
copy

#备注#
atomic修饰的属性: 可以保证对该成员变量的赋值和获取数据是线程安全的
栗子🌰
如果我们用atomic修饰了一个数组,那么对这个数组进行赋值和获取,是可以保证线程安全的
但如果我们对数组进行操作,添加或移除对象,那么是不在atomic的负责范围内,所以是没有办法保证线程安全的
assign
  1. 修饰基本数据类型,如int, BOOL等
  2. 修饰对象类型时,不改变其引用计数
  3. 会产生悬垂指针: assign所修饰的对象,在被释放之后,assign指针仍指向原对象内存地址,如果这时通过assign指针,继续访问原对象,会导致内存泄露或程序异常
weak
  1. 不改变被修饰对象的引用计数,一般使用weak是用来解决循环引用问题
  2. 所修饰的对象在被释放之后会自动置为nil
weak和assign的区别
  1. weak可以修饰对象,assign既可以修饰对象,也可以修饰基本数据类型
  2. weak所修饰的对象,在被废弃之后,weak指针置为nil. assign所修饰的对象,在被释放之后,assign指针仍指向原对象内存地址
weak和assign的联系

在修饰对象时,weak和assign都不改变被修饰对象的引用计数

weak所修饰的对象,在被废弃之后,为什么置为nil(内存管理)
copy
#NSMutableArray用copy修饰会出现什么问题?#
@property (copy) NSMutableArray *array;

浅拷贝:是指针拷贝,是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间

指针A指向某个对象的内存,对象在内存当中用黑框表示,若此时对对象A进行浅拷贝,就会有个B指针指向和A同一块的内存地址
所以说,浅拷贝是对内存地址的复制,但是并没有对内存空间复制,A和B两个指针是指向了同一片内存空间

浅拷贝的特点

1.浅拷贝会增加被拷贝对象的引用计数,上图的引用计数就是2
2.并没有发生新的内存分配,两个指针指向同一块原来的内存空间

深拷贝:是内存拷贝,是让目标对象指针和源对象指针分别指向两片内容相同的内存空间

指针A指向某个对象的内存,对象在内存当中用黑框表示,若此时对对象A进行深拷贝,就会产生新的内存分配,然后会有一个新的指针B,指向这块新的内存
两片内存空间只是内容相同,但不是同一块内存空间

深拷贝的特点
  1. 不会增加被拷贝对象的引用计数,因为没有新指针指向原来的内存空间
  2. 产生了新的内存分配,出现了两块内存
深拷贝和浅拷贝的区别
  1. 是否开辟了新的内存空间
    深拷贝开辟了新的内存空间,浅拷贝没有开辟

  2. 是否影响了引用计数
    深拷贝没有影响,浅拷贝增加了引用计数

copy关键字的使用
  1. 可变对象的copy和mutableCopy都是深拷贝
  2. 不可变对象的copy是浅拷贝,mutableCopy是深拷贝
  3. copy方法返回的都是不可变对象,若被拷贝对象是可变对象,返回的也是不可变对象


#NSMutableArray用copy修饰会出现什么问题?#
@property (copy) NSMutableArray *array;

若上面的NSMutableArray类型的array被copy修饰,会导致程序异常
因为如果赋值过来的是NSMutableArray对象A,会对可变对象A进行copy操作,拷贝结果是不可变的,那么copy后就是NSArray
如果赋值过来的是NSArray对象B,会对不可变对象B进行copy操作,拷贝结果仍是不可变的,那么copy之后仍是NSArray
所以不论赋值过来的是什么对象,只要对NSMutableArray进行copy操作,结果一定是不可变的

但因为原来属性声明的是NSMutableArray,就会调用添加或者移除方法
但因为拷贝后的结果是不可变对象,所以一旦调用这些方法就会程序崩溃!!!
MRC下如何重写retain修饰变量的setter方法

很多公司的app大多很早之前就产生了,那个时候,有很多文件是使用MRC的,所以需要了解MRC知识

@property (nonatomic, retain)id obj;
- (void)setObj:(id)obj
{
    if (_obj != obj) {
        [_obj release];
        _obj = [obj retain];
    }
}

/*
retain和内存管理相关
在set方法里先判断,如果传进来的对象不是原来的对象,那么要先对原来的对象进行release操作
然后对新传来的值进行retain操作,再赋值给成员变量
为什么先做不等的判断,不是因为避免相等情况下走多次造成不必要的开销.而是因为:
如果传递进来的obj对象恰好就是原来的对象的话,先对原对象进行release操作,实际上也是对传递进来的对象进行release操作
那么很可能传进来的这个obj对象就被我们无辜释放了,再做 [obj retain]就会异常
所以要做不等判断,主要是为了防止异常处理
*/
上一篇 下一篇

猜你喜欢

热点阅读