iOS属性关键字

  • @property
    相当于声明了setter和getter方法
ivar + getter + setter

对应runtime底层的objc_property_t
struct property_t { const char *name; const char *attributes; }; 其中 attributes 本质是 objc_property_attribute_t typedef struct { const char *name; /**< The name of the attribute */ const char *value; /**< The value of the attribute (usually empty) */ } objc_property_attribute_t; attributes具体内容包括类型 原子性内存语义 实例变量@property (nonatomic, strong) NSArray *array;

通过 property_getAttributes(property) 获取到 attributes,完成属性的定义,编译器会自动编写访问这些属性的所需方法,这个过程叫做自动合成(autosynthesis)
这个过程是在编译期中完成的,编译器中看不到对应的合成方法(synthesized method)源代码,除了生成方法代码 getter、setter 之外,编译器还要自动向类中添加适当类型的实例变量,并且在属性名前面加下划线,以此作为实例变量的名字。
@property (nonatomic, strong) id selectControl;

会生成两个实例变量,其名称分别为 _selectControl或者在类的实现代码里通过 @synthesize 语法来指定实例变量的名字.
@synthesize _ selectControl = selectControl;

添加属性的过程:
1、在var_list(成员变量列表)中添加一个成员变量的描述
2、在method_list(方法列表)中添加setter getter方法的描述
3、在prop_list属性列表中添加属性的描述
  • @synthesize 和 @dynamic
1、@synthesize 语义是系统会自动帮你生成setter和getter方法,然后生成一个对应的实例变量名
@property (nonatomic, strong) id selectControl; //生成一个_selectControl的实例变量名,_selectControl可以根据自己需求更改, //如果不声明 @synthesize,则默认下方的操作 @synthesize _ selectControl = selectControl;

2、@dynamic 语义是用户要求自动生成setter getter方法,系统不会自动生成,所以此时调用setter或getter方法会crash,编译不报错(oc的动态绑定机制),而且调用对应的实例变量会报错
  • assign
    用来修改基本数据类型和对象,不涉及内存管理,内存计数不变化,所以如果修饰对象类型的话(一般编译的时候会产生警告:Assigning retained object to unsafe property; object will be released after assignment)会出现野指针或者EXC_BAD_ACCESS错误,因为如果对象被释放后,不会对指针地址进行置nil操作
  • retain
    引用计数+1,对应的setter方法
- (void) setStr:(NSString *)str{ if (_oldStr !=str){ [_oldStr release] _oldStr = [str retain]; } }NSString *str0 = [str retain]; //str0 和 str 的变量地址相同,指向相同的内容地址,str 的retainCount增加1此对象只能用于Object-c对象类型,而不能用于Core Foundation对象。(基本数据类型 和 CoreFoundation 对象都没有引用计数)当把对象添加到 数组中时,被添加对象的引用计数+1

  • copy
1、指针复制,释放旧对象,然后生成一个计数为1的新对象
- (void) setStr:(NSString *)str{ if (_oldStr !=str){ [_oldStr release] _oldStr = [str copy]; } }

2、一般用来修饰符合NSCopying协议的类型
3、涉及到浅拷贝和深拷贝
1、对不可变对象执行copy操作,是浅拷贝(指针拷贝,内容相同),都指向同一边存储空间,源数据被修改,副本数据也会被修改 2、对不可变字符串执行mutCopy操作,是深拷贝(对象拷贝),两者指向不同的存储空间 3、可变字符串执行copy或mutCopy都是深拷贝 4、可变容器类执行copy或mutcopy或者不可变容器执行mutCopy都是不完全深拷贝,即只是容器对象指向不同的内存空间,内部的元素则指向同一个内存 5、可变数组执行copy(NSMutableArray执行copy后返回的NSArray),在使用过程回出现crash的问题 6、数组完全深拷贝需要执行initWithArray:copyItems: 方法 NSArray *deepCopy = [[NSArray alloc] initWithArray:array copyItems:YES];

4、NSString类型用copy修饰的原因
@interfaceobj : NSObject @property (nonatomic,copy) NSString *str; @end//实例化后赋值 obj.str = copyStr;

如果str用strong修饰(strong赋值操作参考下方),而copyStr是可变类型,则上面的赋值操作后,str同copyStr一样指向同一块内存空间,这样如果copyStr发生改变,str也会跟着改变,数据就会出现被篡改的风险;
如果用copy修饰,copy对可变对象执行深拷贝,拷贝出一个新的内存空间,这样就互不影响了
  • weak
【iOS属性关键字】1、弱引用,不会持有对象,也就不会有引用计数的变化,一般用来避免循环引用的问题,如果对象被释放,则对应的指针变量会置nil(runtime消息发送机制,对nil发送消息返回空,不会出现异常)
2、weak底层是通过sideTab中的hash表进行管理的,通过对象指针作为key,对应的weak指针数组作为value进行存储,一旦对象被释放,就会通过该对象地址在表中进行查找对应的weak指针数组,然后遍历进行置nil操作
3、与assign的区别
weak修饰的对象销毁的时候,指针会自动设置为nil,而assign不会
4、xib/Storyboard中,系统会自动为控件赋strong,所以拖到代码一般用weak

iOS属性关键字
文章图片
266345-0c09f2ef2d7ee7ae.png
  • strong
1、强引用,持有对象,引用计数+1,用于延长对象的生命周期
- (void) setStr:(NSString *)str{ if (_oldStr !=str){ [str retain ]; [_oldStr release]; _oldStr = str; } }

2、一般的指针变量默认是strong类型
  • atomic和nonatomic
1、原子属性,线程安全,读写有加锁(互斥锁)操作,防止多条线程同时访问同一块内存,但是需要消耗大量资源
2、atomic只是对属性的getter/setter方法进行了加锁操作,这种安全仅仅是set/get 的读写安全,并非真正意义上的线程安全,因为线程安全还有读写之外的其他操作(比如:如果当一个线程正在get或set时,又有另一个线程同时在进行release操作,可能会直接crash)
3、非原子属性,不加锁,当多个线程同时访问同一个属性,会出现无法预料的结果,但是性能更好

    推荐阅读