记录objc学习中的一些技术点。
[TOC]
####nonatomic 非原子操作,没有线程锁,效率高
####atomic
默认属性关键字之一,原子操作,由于系统给加的线程锁,效率低。只能保证set
get
方法的线程安全,不能保证对于成员变量访问的绝对安全和数据的一致性,比如在一个线程 thread1 内进行:
//对于某个对象obj,存在属性@proprety(atomic,readwrite) int i;
for(int i = 0;i < 1000;i++)
{
NSLog(@"%d",obj.i);
}
而存在另外一个并发执行的线程 thread2 ,在某个时刻执行:
obj.i = 10;//set
这可能会导致 thread1 输出不一致。
而有些情况,如:
@interface SomeClass : NSObject
@property (atomic, retain) NSMutableArray *mArray;
@end
同时存在某个线程 thread1 、thread2 对于SomeClass
的实例 obj 执行如下操作:
for(int i = 0;i < 1000;i++)
{
[obj.mArray addObject:[NSNumber numberWithInt:i]];
}
@end
将可能会出现多线程访问冲突。 综上:atomic 并不能绝对保证多线程的安全。
####readonly
只读权限,默认不会合成set
方法。
####readwrite 可读写权限。 如果不显示声明则默认为readwrite。
####assign 可以用于C数据类型以及类类型对象,作用于类类型对象时,不会增加引用计数,目标对象释放后不会置为nil。
####unsafe_unretained 作用同assign。
####retain
对原对象release
,对目标对象retain
。只能作用于类类型对象,会增加引用计数而强引用到目标对象。
####strong
作用同retain,ARC
下默认关键字之一。
####copy
对原对象release
,对目标对象进行copy
操作并指向copy后指向copy
后的地址。不能作用于C数据类型,目标对象必须实现NSCopying
协议。
####weak
在ARC
下使用,对目标对象进行弱引用,当目标对象释放后会置为nil。
####说明及注意
MRC
下默认关键字:atomic
readwrite
assign
ARC
下默认关键字:atomic
readwrite
strong
在ARC
环境下,对于变量可以用__weak
__strong
__unsafe_unretained
__autoreleasing
来修饰以控制变量是否进行强引用等行为。而默认值是__strong
。例如:
NSObject * obj = [NSObject alloc] init];
//
NSObject * obj1 = obj;
__strong NSObject * obj2 = obj;//
__weak NSObject * objc3 = obj;
obj1 与 obj2 都会对 obj 进行强引用,而 objc3 为弱引用。
__autoreleasing
关键字对用于函数返回值,当需要返回某个对象时,系统会默认给加上。
需要注意的是,ARC
中的成员变量其默认修饰关键字为__strong
,所以如下写法会出现编译错误:
@interface SomeClass : NSObject
{
NSObject * _obj;
}
@property (nonatomic, weak) NSObject *obj;
@end
@implementation SomeClass
@end
声明为(nonatomic,copy)
的属性,在调用set
方法时,会调用objc_setProperty_nonatomic_copy
,然后调用copyWithZone
方法。
声明为(atomic,copy)
的属性,在调用set
方法时,会调用objc_setProperty_atomic_copy
,然后调用copyWithZone
方法。
####对于copy
(mutableCopy
)的进一步说明
NSObject类中存在一些方法:
+(instancetype)alloc;
+ (instancetype)allocWithZone:(struct _NSZone *)zone;
- (id)copy;
- (id)mutableCopy;
+ (id)copyWithZone:(struct _NSZone *)zone;
+ (id)mutableCopyWithZone:(struct _NSZone *)zone;
其中后两个方法是为类对象
服务的,以便让类对象
存放到容器中,但类对象
全局只需要一份,所以只需要直接返回self
,如下:
+ (id)copyWithZone:(struct _NSZone *)zone
{
return self;
}
+ (id)mutableCopyWithZone:(struct _NSZone *)zone
{
return self;
}
对于+(instancetype)alloc
方法,将直接返回+ (instancetype)allocWithZone:(struct _NSZone *)zone
的返回值,由于NSZone已经被废弃,所以直接传入NULL
,如下:
+ (id)alloc
{
return [self allocWithZone:NULL];
}
对于- (id)copy
方法,将直接返回NSCopying
协议中的- (id)copyWithZone:(nullable NSZone *)zone
的返回值,如下:
- (id)copy
{
return [self copyWithZone:NULL];
}
但NSObject并没有实现- (id)copyWithZone:(nullable NSZone *)zone
方法,所以如果需要copy
则需要子类实现此方法。
同理对于- (id)mutableCopy
方法,则需要实现NSMutableCopying
中的- (id)mutableCopyWithZone:(nullable NSZone *)zone
方法。
对于
NSArray * array = [NSArray arrayWithObjects:/*some objects*/, nil];
NSMutableArray * mArray = [NSMutableArray array];
[mArray addObject:/*some object*/];
会对目标对象进行retain
操作,而不是 copy
操作。
对系统容器类进行copy
或者mutableCopy
的说明:
以下以Array类为例,对于Dictionary 或者 Set 其行为类似。
对NSArray 的实例对象 array进行copy
操作:
返回值为[array retain]
后的地址,及只会对array进行retain
,而不会重新分配内存。另外 array 中的所有元素没有进行retain
操作。
对NSArray 的实例对象 array2进行mutableCopy
操作:
返回值为NSMutableArray类对象,地址与array2 不同,retainCount
为1
,并且对array2中的所有元素进行retain
(注意不是copy
或者mutableCopy
)操作。
对NSMutableArray 的实例对象 mArray进行copy
操作:
返回值为NSArray类对象,地址与mArray 不同,retainCount
为1
,并且对mArray中的所有元素进行retain
操作。
对NSMutableArray 的实例对象 mArray2 进行mutableCopy
操作:
返回值为NSMutableArray类对象,地址与mArray2 不同,retainCount
为1
,并且对mArray2 中的所有元素进行retain
操作。
在实际开发过程中:
- 对于祖先链上无
- (id)copyWithZone:(nullable NSZone *)zone
方法的,直接调用
- (id)copyWithZone:(nullable NSZone *)zone
{
id res = [[self class] allocWithZone:zone];
//对其他成员变量复制或者赋值
//
return res;
}
注意这里用[self class]
而不是用具体的类名,否则子类再重写此方法时会有问题:alloc
出来的会是父类类型而不是子类类型,不会包含子类中的成员变量等。
2. 对于祖先链上有- (id)copyWithZone:(nullable NSZone *)zone
方法的,直接调用:
- (id)copyWithZone:(nullable NSZone *)zone
{
id res = [super copyWithZone:zone];
//对本类的其他成员变量复制或者赋值
//
return res;
}
先调用父类中的方法,然后对本类中的成员变量处理。
3. 对于非mutable对象,仅仅对本对象retain
即可,当然也是根据自己需求灵活调整。