Joostar / Objective-C-Points

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Objective-C-Points

标签: Objetive-C

记录objc学习中的一些技术点。


[TOC]


###1.内存管理,各种属性关键字意义、区别

####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 

同时存在某个线程 thread1thread2 对于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 作用同retainARC下默认关键字之一。


####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;

obj1obj2 都会对 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方法。


####对于copymutableCopy)的进一步说明


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 不同retainCount1,并且对array2中的所有元素进行retain(注意不是copy或者mutableCopy)操作。


NSMutableArray 的实例对象 mArray进行copy操作: 返回值为NSArray类对象,地址与mArray 不同retainCount1,并且对mArray中的所有元素进行retain操作。

NSMutableArray 的实例对象 mArray2 进行mutableCopy操作: 返回值为NSMutableArray类对象,地址与mArray2 不同retainCount1,并且对mArray2 中的所有元素进行retain操作。


在实际开发过程中:

  1. 对于祖先链上 - (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即可,当然也是根据自己需求灵活调整。

About

License:GNU General Public License v3.0