读写属性:readwrite
、readonly
setter语意:assign
、retain
/ copy
原子性(多线程管理):atomic
、 nonatomic
强弱引用:strong
、 weak
html
读写属性:
readwrite
:同时生成 set
和 get
方法(默认)
readonly
:只会生成 get
方法ios
控制set方法的内存管理:
retain
:release
旧值,retain
新值。但愿得到源对象的全部权时,对其余 NSObject
和其子类(用于 OC
对象)
copy
:release
旧值,copy
新值。但愿得到源对象的副本而不改变源对象内容时(通常用于 NSString
,block
)
assign
:直接赋值,不作任何内存管理(默认属性),控制需不需生成 set
方法。对基础数据类型 (NSInteger
,CGFloat
)和C数据类型(int
, float
, double
, char
, 等等),另外还有id类型segmentfault
原子性(多线程管理):数组
atomic
nonatomic
@synchronized
(变量)来对该变量进行加锁(加锁的目的经常是为了同步或保证原子操做)。强指针(strong)、弱指针(weak)安全
strong
strong
系统通常不会自动释放,在 oc
中,对象默认为强指针。做用域销毁时销毁引用。在实际开放中通常属性对象通常 strong
来修饰(NSArray
,NSDictionary
),在使用懒加载定义控件的时候,通常也用strong。weak
weak
所引用对象的计数器不会加一,当对象被释放时指针会被自动赋值为 nil
,系统会马上释放对象。__unsafe_unretained
弱引用 当对象被释放时指针不会被自动赋值为 ni
assign
的(至关于 __unsafe_unretained
)retain
的 (至关于 __strong
)sb
或者 xib
给控件拖线的时候,为何拖出来的先属性都是用 weak 修饰呢?xib
或者 sb
里面添加控件的时候,添加的子视图是添加到了跟视图 View
上面,而 控制器 Controller
对其根视图 View
默认是强引用的,当咱们的子控件添加到 view
上面的时候,self.view addSubView:
这个方法会对添加的控件进行强引用,若是在用 strong
对添加的子控件进行修饰的话,至关于有两条强指针对子控件进行强引用, 为了不这种状况,因此用 weak
修饰。ARC管理内存是用 assign
仍是用 weak
?
assign
: 若是因为某些缘由代理对象被释放了,代理指针就变成了野指针。
weak
: 若是因为某些缘由代理对象被释放了,代理指针就变成了空指针,更安全(weak
不能修饰基本数据类型,只能修饰对象)。bash
weak的做用:
weak
关键字的做用弱引用,所引用对象的计数器不会加一,并在引用对象被释放的时候自动被设置为 nil
,大大避免了野指针访问坏内存引发崩溃的状况,另外 weak
还能够用于解决循环引用。服务器
使用场景:
用于一些对象相互引用的时候,避免出现强强引用,对象不能被释放,出现内存泄露的问题。多线程
实现原理:
runtime
维护了一个 weak
表,用于存储指向某个对象的全部 weak
指针。weak
表实际上是一个hash(哈希)表,Key
是所指对象的地址,Value
是 weak
指针的地址(这个地址的值是所指对象的地址)数组。(备注:strong
是经过 runtime
维护的一个自动计数表结构)
weak 的实现原理可归纳三步:并发
runtime
会调用 objc_initWeak
函数,初始化一个新的 weak
指针指向对象的地址。objc_initWeak
函数会调用 objc_storeWeak()
函数, objc_storeWeak()
的做用是更新指针指向,建立对应的弱引用表。clearDeallocating
函数。clearDeallocating
函数首先根据对象地址获取全部 weak
指针地址的数组,而后遍历这个数组把其中的数据设为 nil
,最后把这个 entry
从 weak
表中删除,最后清理对象的记录。文章推荐:
iOS 底层解析weak的实现原理(包含weak对象的初始化,引用,释放的分析)
浅谈iOS之weak底层实现原理app
retain
操做// 深复制:产生了新对象,新对象(副本对象)的计数器是1, 源对象的计数器不变
// str : 1
NSString *str = [NSString stringWithFormat:@"Tom"];
// str2 : 1
NSMutableString *str2 = [str mutableCopy];
NSLog(@"str=%zd, str2=%zd", [str retainCount], [str2 retainCount]);
[str2 release];
复制代码
// 浅复制:没有产出新对象, 源对象(副本对象)的计数器会+1
NSString *str = [NSString stringWithFormat:@"Jack"];
NSString *str2 = [str copy];
[str2 release];
NSLog(@"%zd", [str retainCount]);
复制代码
copy
产生不可变副本,mutableCopy
产生可变副本
copy
和
mutableCopy
),只是Foundation库中的类的对象能够直接复制,自定义的类的对象须要作一些额外的工做才能复制,但实际作app几乎不须要复制自定义类的对象。
copy
、mutableCopy
对比不可变对象 copy
成 不可变对象 是浅复制,其余都是深复制。(不可变对象指NSArray、NSDictionary、NSString等)
NSMutableArray
被 copy
、strong
修饰后的变化 把NSMutableArray用copy修饰有时就会crash,由于对这个数组进行了增删改操做,而copy后的数组变成了不可变数组NSArray,没有响应的增删改方法,因此对其进行增删改操做就会报错。 举例以下:
NSMutableArray *b = [NSMutableArray array];
a = b;
复制代码
@property (nonatomic, copy) NSMutableArray *a;
NSMutableArray *b = [NSMutableArray array];
// a被copy后就成了NSArray了。
a = [b copy];
复制代码
@property (nonatomic, strong) NSMutableArray *a;
若是是 strong
,直接是赋值 a = b
;右边是什么,左边就是什么,而且是强引用新值,左边的类型会与右边的相同,不会改变。iOS 深拷贝浅拷贝与@property 引用计数关键字Strong,Copy,Weak,Assign
iOS 浅谈:深.浅拷贝与copy.strong
数组的属性修饰符到底用strong仍是copy?
iOS中copy和mutableCopy的详细分析
咱们经过实际操做来讲明,咱们把str赋值给 zhangsan
的 name
属性,而后去改变 str
,结果: 用 @property (nonatomic, retain) NSString *name;
修饰的name答应结果为 zhangsanabc
,name
属性被修改了; 用 @property (nonatomic, copy) NSString *name;
修饰的 name
答应结果为 zhangsan
,name
属性没有被修改。
NSMutableString *str = [NSMutableString string];
str.string = @"zhangsan";
Person *zhangsan = [[[Person alloc] init] autorelease];
zhangsan.name = str;
[str appendString:@"abc"];
NSLog(@"%@ %@", str, zhangsan.name);
复制代码
下面咱们来看代码set方法的内部实现: 当.h用@property (nonatomic, retain) NSString *name;
时,_name = [name retain];
至关于[name retain]
和 _name = name;
,而这两句话至关因而先把原来的做引用计数+1,再把指针付给 _name
,实际上指向的是一块内存,这样会致使原来的内容改变,_name
也会改变,而实际中咱们通常不但愿 _name
改变,因此咱们不用retain。
- (void)setName:(NSString *)name {
if (_name != name) {
[_name release];
_name = [name retain];
//_name = [name retain];至关于下边两句,而这两句话至关因而先把原来的做引用计数+1,再把指针付给_name,实际上指向的是一块内存,这样会致使原来的内容改变,_name也会改变,而实际中咱们通常不但愿_name改变,因此咱们不用retain
// [name retain];
// _name = name;
}
}
- (void)dealloc {
// [_name release];
// _name = nil;
self.name = nil;
[super dealloc];
}
复制代码
当.h用@property (nonatomic, copy) NSString *name;
时,当传入的值为可变对象时,调用_name = [name copy];
copy
会建立一个新的对象赋值给 _name
,因此 _name
和 name
是两块无关的内容,改变 name
不会影响 _name
- (void)setName:(NSString *)name {
if (_name != name) {
[_name release];
// 当传入的值为可变对象时,copy会建立一个新的对象赋值给_name,因此_name和name是两块无关的内容,改变name不会影响_name
_name = [name copy];
}
}
- (void)dealloc {
// [_name release];
// _name = nil;
self.name = nil;
[super dealloc];
}
复制代码
@synthesize propertyName
,编译器先会查找这个属性名的setter方法和getter方法有没有被人为实现,若是已经实现,则再也不实现,若是没有,则会帮咱们生成一个属性命的setter方法和getter方法。@synthesize propertyName
,编译器还会作一件事情,在类成员变量中查找一个名为 _propertyName
的成员变量,若是没有,再继续查找名为 propertyName
的成员变量,若是这两个都没有,编译器会自动为咱们生成一个私有的名为 _propertyName
的成员变量。注意,系统自动建立的都是私有的。@synthesize propertyName = varName
;时,setter
和 getter
方法所对应的是一个名为 varName
的成员变量,修改和读取的是 varName
成员变量的值。@synthesize propertyName
时,在Xcode 4.5以前的版本不会帮咱们自动实现 setter
和 getter
方法,系统固然也再也不会为咱们生成对应的成员变量。可是在Xcode 4.5以后能够不用写@synthesize了,就跟三、4同样了。@synthesize
,又在实现文件中人为重写 setter
和 getter
方法时,那么 @synthesize
将再也不工做,也就不会为咱们建立没有定义的 _propertyName
成员变量了,这时候若是在 setter
和 getter
方法中调用 _propertyName
将会发生编译错误