@property中的关键字:https://www.jianshu.com/p/3709cf8f8937
成员变量和属性的区别:https://www.jianshu.com/p/16692335eb41
1. @property做了些什么?
当我们写下property NSObject *foo;
时,编译器为我们做了三件事
- 创建实例变量_foo
- 声明foo属性的setter和getter方法
- 实现foo属性的setter和getter方法
@property的本质是什么?
@property = ivar(实例变量) + getter(get方法) + setter(set方法);
也就是说使用@property 系统会自动生成setter和getter方法;
2. atomic和nonatomic
- atomic和nonatomic会决定编译器生成的setter和getter方法是否为原子操作,即会保证setter和getter的完整性。如果有多个线程同时调用setter的话,相当于函数头尾加了锁一样,每次只能有一个线程调用对象的setter方法,所以可以保证数据的完整性。
- 被atomic修饰的属性任何线程对其访问,都能获得一个完整初始化后的对象,用nonatomic修饰则不一定能保证。
- 因为要保证完整性,所以atomic比nonatomic要慢。
- atomic所说的线程安全只是保证了getter和setter存取方法的线程安全,并不能保证整个对象是线程安全的。
举例:
如果线程 A 调了 getter,与此同时线程 B 、线程 C 都调了 setter——那最后线程 A get 到的值,有3种 可能:可能是 B、C set 之前原始的值,也可能是 B set 的值,也可能是 C set 的值。同时,最终这个属性 的值,可能是 B set 的值,也有可能是 C set 的值。所以atomic可并不能保证对象的线程安全。
-
atomic与nonatomic的本质区别其实也就是在setter方法上的操作不同
-
atomic 修饰的对象,系统会保证在其自动生成的 getter/setter 方法中的操作是完整的,不受其他线程的影响。例如 A 线程在执行 getter 方法时,B线程执行了 setter 方法,此时 A 线程依然会得到一个完整无损的对象。
总结:
atomic
- 默认修饰符
- 会保证CPU能在别的线程访问这个属性之前先执行完当前操作
- 读写速度慢
- 线程不安全 - 如果有另一个线程 D 同时在调[name release],那可能就会crash,因为 release 不受 getter/setter 操作的限制。也就是说,这个属性只能说是读/写安全的,但并不是线程安全的,因为别的线程还能进行读写之外的其他操作。线程安全需要开发者自己来保证。
nonatomic
- 不默认
- 速度更快
- 线程不安全
- 如果两个线程同时访问会出现不可预料的结果。
3.assign
- 这个关键字一般用在基本数据类型,比如如NSInteger和CGFloat等,如果不用其他关键词修饰,默认用assign
- assign也可以用来修饰对象,但是对象的计数不会+1
- 如果assign用来修饰对象,当对象被销毁后指针不会指向nil,所以会出现野指针。如果assign用来修饰基本数据类型则不会发生这种情况,因为基本数据类型被存储在栈上管理,栈内存会被自动回收,所以一般用assign修饰基本数据类型
4. weak
- weak一般用来修饰OC对象,表示指向但不拥有该对象,不会使对象的引用计数+1,当该对象被释放时,会自动设置为nil。
weak的原理
- Runtime中维护了一个weak表(hash表),用于存储某个对象的所有weak指针。在这个表中,key是所指对象的地址,value是一个数组,里面装的是weak指针的地址(因为一个对象可能被多个弱引用指针指向)。
weak的实现步骤
NSObject *obj = [[NSObject alloc] init];
id __weak obj1 = obj;
当weak修饰的对象被释放时,weak指针的处理流程
- 调用objc_release
- 因为对象的引用计数为0,所以执行dealloc
- 在dealloc中,调用了 _objc_rootDealloc函数 -> 调用了object_dispose函数 -> 调用objc_destructInstance -> 最后调用objc_clear_deallocating
- objc _ clear _ deallocating该函数的动作如下:
- 从weak表中获取废弃对象的地址为键值的记录
- 将包含在记录中的所有附有 weak修饰符变量的地址,赋值为nil
- 将weak表中该记录删除
- 从引用计数表中删除废弃对象的地址为键值的记录
5. copy
小结iOS中的copy:https://www.jianshu.com/p/5254f1277dba
预备知识
- 浅拷贝 :只是将对象内存地址多了一个引用,也就是说,拷贝结束之后,两个对象的值不仅相同,而且对象所指的内存地址都是一样的。
- 深拷贝 :拷贝一个对象的具体内容,拷贝结束之后,两个对象的值虽然是相同的,但是指向的内存地址是不同的。两个对象之间也互不影响,互不干扰。
- copy拷贝出来的对象类型总是不可变类型(例如, NSString, NSDictionary, NSArray等等),mutableCopy拷贝出来的对象类型总是可变类型(例如, NSMutableString, NSMutableDictionary, NSMutableArray等等)
copy的作用
- copy与strong类似。不同之处是strong的复制是多个指针指向同一个地址,而copy的复制每次会在内存中拷贝一份对象,指针指向不同地址。copy一般用在修饰【有可变对应类型】的不可变对象上,如NSString, NSArray, NSDictionary。
网友评论