介绍
- 简介:属性(property)是Objective-C的一项特性,用于封装对象中的数据。这一特性可以令编译器自动编写与属性相关的存取方法,并且保存为各种实例变量。
- 本质:属性的本质是实例变量与存取方法的结合。@property = ivar + getter + setter
特质
原子性相关
atomic
- property 默认是atomic的
- atomic 会保证了对象的原子操作,即atomic会对对象的setter、getter方法加一个锁来保证读写的原子操作;所谓原子操作就是不可分割的操作,在原子操作执行完毕之前,不会被任何其他任务或事件中断。但是atomic并不是线程安全的,如果线程 A 调了 getter,与此同时线程 B 、线程 C 都调了 setter——那最后线程 A get 到的值,有3种可能:可能是 B、C set 之前原始的值,也可能是 B set 的值,也可能是 C set 的值。同时,最终这个属性的值,可能是 B set 的值,也有可能是 C set 的值。所以atomic并不能保证对象的线程安全。
- atomic 消耗性能,访问速度不快,因为要保证操作的整体完整
- 保证CPU能在别的线程来访问这个属性之前,先执行完当前流程
- (void)setAtomicObj:(NSObject *)atomicObj{
@synchronized(self) { // 同步锁
if (_atomicObj != atomicObj) {
[_atomicObj release];
_atomicObj = [atomicObj retain];
}
}
}
- (NSObject *)atomicObj{
@synchronized(self) {// 同步锁
return _atomicObj;
}
}
nonatomic
- 非默认
- 非原子操作,线程不安全
- 访问速度快
内存管理相关
copy
- block 和 字符串、集合中经常使用,这个可以看苹果的 Foundation 中的都是这样使用的
- block 使用copy 是需要把存放在栈内存上的block copy到堆内存中去
- 字符串和 集合使用copy,是因为他们都有mutable子类,当外界传一个可变的子类对象MA给当前属性时A,如果不用copy 的话用strong的话,外界可能会修改这个可变的子类对象MA,这个时候属性A也会发生变化,这样是比较危险的,比如内容一个collectionView执行刷的是后numberofRow返回的结果是10,但是执行到cellfForRowf方法是外部删除了MAde某些元素,这样会导致数组越界崩溃。如果使用copy的话,会重新copy一个新的对象出来,保证外面MA的改变不会波及到属性A
assign
Specifies that the setter uses simple assignment. This attribute is the default. You use this attribute for scalar types such as NSInteger and CGRect.
- 对于基础数据类型property 默认是 assign
- assign 可以用来修饰OC对象吗? 会有什么问题?
assign 可以用来修饰oc对象,assign修饰oc对象会有野指针的问题。因为assign不会强引用对象,如果对象被释放而指针没有置为nil,依然指向该地址,下次访问该对象的时候就会造成野指针。基础数据类型由于是存放在栈内存上的,由系统分配和释放,所以不会有野指针的问题 - assign 和 unsafe_unretain的区别?
我猜想是这样的,assign 是直接赋值的,而unsafe_unretain是引用的,不知道是不是这样的,希望有人指点。 - 使用 assign 修饰成员变量时帮我们生成的 set 方法是没有引用计数的处理的,使用 strong 时是有的
// 使用 strong 修饰时
-(void)setName:(NSString *) name {
if(name != _name){
[_name release];
_name = [name retain];
}
}
// 使用 assign 修饰时
-(void)setName:(NSString *) name {
_name = name;
}
weak
- weak 不会强引用对象,不会对当前对象的引用计数加1,当对象释放的时候指针自动置为nil
- weak 可以用来修饰基础数据类型吗
不可以,如果使用weak修饰基础数据类型xcode会报错
@property (nonatomic, weak) NSInteger age; // Property with 'weak' attribute must be of object type
weak 的原理
1、当使用 weak 关键字初始化一个弱引用对象时,会调用id objc_initWeak(id *location, id newObj)
函数该函数内部调用static id storeWeak(id *location, objc_object *newObj)
函数,location
代表weak 指针的地址,newObj
是被weak
引用的对象。这个函数会根据对象的地址值获取 SideTables 中对应的 sideTable,更具获取的 sideTable 取出sideTable中的weak_table_t,weak_table_t 中存放着一个 weak_enter_t类型的hash 数组,然后会将对象和弱引用对象的地址包装成weak_enter_t类型的结构体,存放到weak_enter_t类型的hash 数组中,当弱引用的对象被释放时,dealloc ->_objc_rootDealloc-> object_dispose -> objc_destructInstance -> objc_clear_deallocating, 最后objc_clear_deallocating函数中会判断对象是否被弱引用过,如果是,就去 sideTable 中的 weak_table_t的 weak_entery_t 类型的列表中找对该对象对应的weak_entery_t然后将里面存放弱引用该对象的地址列表全部置为 nil, 然后将该weak_entery_t从 sideTable 中移除.
strong
- 对于对象类型的 property默认是 strong
- 强引用对象,会对当前对象的引用计数加1
- strong 可以修饰基础数据类型吗?
不可以,strong修饰基础数据类型xcode会报错@property (nonatomic, strong) NSInteger count; // Property with 'retain (or strong)' attribute must be of object type
unsafe_unretained
- 弱引用对象,跟weak区别在于,对象被释放后weak会置为nil,unsafe_unretained不会,所以会有空指针的问题
- unsafe_unretained 可以用来修饰oc对象,也可以修饰基础数据类型(通常不这么做)
@property (nonatomic, unsafe_unretained) NSInteger count;
@property (nonatomic, unsafe_unretained) NSString *home;
读写相关
- 读写权限不写时默认为 readwrite 。一般可在 .h 里写成readonly,只对外提供读取,在 .m 的Extension中再设置为 readwrite 可进行写入。
- readwrite
- readonly
方法名
- 用来指定存取方法的名称
- getter
- setter
值相关
- nonnull
- nullable
延伸
- @dynamic:告诉编译器不要自动创建实现属性所用的实例变量,也不要为其创建存取方法。即使编译器发现没有定义存取方法也不会报错,运行期会导致崩溃。
- @synthesize:在类的实现文件里可以通过 @synthesize 指定实例变量的名称。
类属性
- 今天看
UIDevice
的API突然发现 OC中还有类属性,原来为了配合 swift3 的类属性,OC 也新增了类属性。其本质是为类生成了 set 和 get 方法,但没有生成成员变量,我们可在.m 中声明一个 static 变量来保存值,以便在 set 和 get 中使用
参考链接
@interface UIDevice : NSObject
@property(class, nonatomic, readonly) UIDevice *currentDevice;
网友评论