深入理解OC中的属性
深入理解OC中的属性
传统C++类实例变量写法
- 传统C++实例变量的定义形式 可通过关键字 @public 、@private 、 @protected 以及 @package 等 在头文件中的变量默认是@protected 在.m文件中的变量默认是@private
Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
@public //声明为公有变量
NSString * _name;
@private //限制为私有变量,.m中默认类型
NSString * _ID;
@protected //限制 子类访问变量,.h中默认类型
NSString * _surname;
@package // 包内变量,只能本框架内使用
NSString * _house;
}
@end
以上这种传统定义形式的缺点
-
每个变量都需要手动编写getter和setter方法,变量太多的时候 会写一堆getter setter方法。而oc中属性变量的封装出现就是为了减少此工作以及代码冗余。
-
这种写法属于‘硬编码’,对象内部的变量定义布局已经写死了编译期,编译后不可再更改,否则会出错,因为编译前 被编译器定义为距对象初始指针地址的偏移量,编译之后变量是通过地址偏移来寻找。如果想在类中插入新的变量,那么必须要重新编译计算每个变量的偏移量,否则就会读取错误。
属性变量封装定义
-
存取方法和变量名自动合成
使用OC的属性编译器会严格生成存取方法,通过.语法访问变量的存取方法,(编译器会将.语法转换成存取方法的调用)为了区分实际的变量名在前面加下划线,另外虽然默认加下划线 但是可以通过关键字@synthesize自定义实际的变量名 -
旧版编译器 可能 @property 和@synthesize 是成对出现 因为以前不不会自动生成 setter getter方法
-
@dynamic 禁止自动生成 存取方法
-
通过@property 后的括号内也可以进行限制
#import <Foundation/Foundation.h>
@interface Person2 : NSObject
//只读
@property (nonatomic,copy,readonly) NSString *name1;
@end
5.类主要的属性参数
原子性语义 | atomic 、 nonatomic |
---|---|
读写语义 | readwrite、readonly 、getter、setter |
内存管理语义 | assing 、weak 、unsafe_unretained、retain、strong 、copy |
-
atomic 、nonatomic :原子性和非原子性。原子性是数据库原理里面的一个概念,ACID中的第一个。在多线程中同一个变量可能被多个线程访问甚至更改,进而造成数据污染,因此为了安全,OC中默认是原子性(atomic),即会对setter方法加锁,相应的也会付出维护原子性(数据加锁解锁)的系统资源代价。应用中如果不是多线程通讯变成,那么还是用nonatomic来修饰变量的,不会对setter方法加锁,以提高多线程并发访问时的性能。
-
readonly 、readwrite :readonly表示变量只读,只有get方法 没有set方法 ; readwrite既有get方法,也有set方法 ;可以直接 getter< gettername >,setter= < settername >;可以选择性地在括号里直接指定存取方法的方法名
-
assing: 基本数据类型修饰,不会增加对象引用计数 ;修饰:NSInteger 、int、float、double 、char 等 也可以修饰对指针的弱引用。
-
weak: 修饰弱引用,不增加引用计数,主要用于避免循环引用,和strong/retain对应,功能是上和assing一样 ,不同的weak修饰的对象消失后会自动将指针置位nil,防止‘悬挂指针’
-
unsafe_unretained: 不常用,不安全的,它修饰的不会被编译器进行内存管理,既不是强引用也不是弱引用,生成对象就立刻被释放掉了,出现了所谓的‘悬挂指针’。
-
retain:通常用于引用类型,是为了持有对象,声明强引用,将指针本来指向的旧的引用对象释放掉,然后将指针指向新的引用对象,同时将新对象的索引计数加1。
-
strong 原理和retain类似,只不过在使用ARC自动引用计数时,用strong代替 retain.
-
copy:建立一个和新对象内容相同的对象相同且索引计数为 1的对象,指针指向这个新对象