weak strong 都是 修饰属性的
@property(weak) UIButton *button;
只要有任何strong 指向某个对象A,ARC就不会摧毁它(A)。strong是持有对象
而weak所指向的对象B,只要没有其他strong指向该对象(B),ARC会摧毁它(B)。
StoryBoard 拖出来的为什么是weak?
至于拖出来是weak 是因为:在我们使用SB的时候,系统已经用strong写好了相应的代码只是隐藏起来了.SB拖出可见的只是一个指向指针的指针,不需要持有对象,所以用weak
---------------------------------------------------------------------------------------------------------------------------------------------------
什么是assign,copy,retain之间的区别?
assign: 简单赋值,不更改索引计数(Reference Counting)。
copy: 建立一个索引计数为1的对象,然后释放旧对象
retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1
- copy : 建立一个索引计数为1的对象,然后释放旧对象retain :释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1
那上面的是什么该死的意思呢?
Copy其实是建立了一个相同的对象,而retain不是:
比如一个NSString 对象,地址为0×1111 ,内容为@”STR”
Copy 到另外一个NSMutableString 之后,地址为0×2222 ,内容相同,新的对象retain为1 ,旧有对象没有变化
retain 到另外一个NSMutableString 之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1
也就是说,retain 是指针拷贝,copy 是内容拷贝。哇,比想象的简单多了…
举例说明 先运行 test 再运行 test2
@interface ViewController ()
@property (nonatomic,copy) NSString *name;
@property (nonatomic,retain) NSString *name2;
@end
-(void)test{
NSString *str = @"fffff";
self.name = str;
self.name2 = str;
NSLog(@" str: %p",str);
NSLog(@" copy: %p",self.name);
NSLog(@"retain: %p",self.name2);
}
-(void)test2{
NSMutableString *str = [NSMutableString stringWithString:@"ffffff"];
self.name = str;
self.name2 = str;
NSLog(@" strM: %p",str);
NSLog(@" copy: %p",self.name);
NSLog(@"retaini: %p",self.name2);
}
test 运行
str: 0x94
copy: 0x94
retaini: 0x94
test2 运行
str: 0x94
copy: 0x00
retaini: 0x94
如果把一个对象赋值给另一个对象(如上面把str赋值给name或name2),如果该对象是不可变的,那么另一个对象是copy或者retain都可以,没区别;把一个对象赋值给另一个对象,如果该对象是可变的,并且希望另一个对象随着该对象变化而变化,则可以把另一个对象设置为retain(如上面把str赋值给name2);如果希望另一个对象不随着该对象变化而变化,则可以把另一个对象设置为copy(如上面把str赋值给name)。
??为什么说不希望值改变时 用 copy 下边会给实际例子!!!!!!!!
如下所示,当修饰符为copy时,因为NSMutableString是NSString类型的子类,所以可以用指针self.name指向mStr,但是我们知道copy的含义是指当重新赋值时深拷贝新对象再赋值给self.name,
所以此时self.name的指针和mStr的指针指向的对象就不同了,所以当给mStr对象发送方法appendString的时候,修改的只是mStr(此时的值变为mutablestring----addstring),而self.name依然不变(mutablestring----);相反当修饰符为strong时,因为strong的意思是指针指向原对象,并且引用计数+1,所以self.name和mStr指向同一个对象,当修改mStr时self.name也会一起变化。所以为了避免NSString类型的值被修改,一般建议用copy修饰符修饰。
@interface ViewController ()
@property (nonatomic,copy) NSString *name;
//@property (nonatomic,strong) NSString *name;
@end
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableString *mStr = [NSMutableString stringWithFormat:@"mutablestring----"];
self.name = mStr;
[mStr appendString:@"addstriing"];//name的修饰符为copy时,name的结果为mutablestring----
NSLog(@"%@",mStr);//name的修饰符为strong时,name的结果为mutablestring----addstriing
NSLog(@"%@",self.name);
}
关于深浅拷贝上篇文章会说明
-----------------------------------------------------------------------------------------------------------------------------------------------------
weak 和strong的区别:
(weak和strong)不同的是 当一个对象不再有strong类型的指针指向它的时候 它会被释放 ,即使还有weak型指针指向它。
一旦最后一个strong型指针离去 ,这个对象将被释放,所有剩余的weak型指针都将被清除。
可能有个例子形容是妥当的。
想象我们的对象是一条狗,狗想要跑掉(被释放)。
strong型指针就像是栓住的狗。只要你用牵绳挂住狗,狗就不会跑掉。如果有5个人牵着一条狗(5个strong型指针指向1个对象),除非5个牵绳都脱落 ,否着狗是不会跑掉的。
weak型指针就像是一个小孩指着狗喊到:“看!一只狗在那” 只要狗一直被栓着,小孩就能看到狗,(weak指针)会一直指向它。只要狗的牵绳脱落,狗就会跑掉,不管有多少小孩在看着它。
只要最后一个strong型指针不再指向对象,那么对象就会被释放,同时所有的weak型指针都将会被清除。
使用assign: 对基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float, double, char, 等等)
使用copy: 对NSString
使用retain: 对其他NSObject和其子类
nonatomic关键字:
atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。
二.必要的知识补充.
- 众所周知,OC是一门面向对象的语言,因此,对象这个词,在iOS中是个非常重要的词汇了(扯淡).开发中,创建一个对象是再常见不过的事儿了,每个对象的创建都需要在内存中分配一定的空间,简单的说,因为内存是有限的,所以一些没有必要存在的对象,我们需要及时的去将它释放,还原更多的内存空间(如果不进行释放就会造成"内存泄露").
- 因此,在iOS中引入了引用计数(retainCount)这个词汇,规定:只要引用计数为零,对象就会被释放,注意是规定,规定就不要问为什么了.
- 这里主要介绍strong和weak两个修饰词(不能偏离重点),如果想了解其他的修饰词(retain,copy,getter,setter...),可以Google一下,简单点来讲strong属性会使引用计数+1,而weak修饰的对象不会使引用计数改变.
- OK了,有了上面的只是准备,应该可以理解下面的要解释的东西了.
三.案例说明
- 案例介绍
```
案例中的类介绍: 案例共用到三个类,Baby类(婴儿类),LLBabyServant类(保姆类),ViewControllr类(控制器类),其中说明问题的关键是之前两个类.
假设,婴儿类要想做一些事情(像换衣服了,方便了之类的...)就必须具有代理的属性,因此指定了一个协议<LLBabyDelegate>,合情合理.而保姆需要成为婴儿的代理,必须遵循协议,废话不多说,上代码!
```
- 首先介绍Baby类-----.h文件
```
// 制定协议
@protocol LLBabyDelegate <NSObject>
//这里可以编写代理方法(该案例中用不到所以就不写了)
@end
@interface Baby : NSObject
/**
* baby的代理属性(这里用的是weak修饰,正确的做法)
*/
@property(nonatomic, weak) id<LLBabyDelegate>delegate;
@end
```
说明:跟上面描述的一样婴儿拥有一个代理的属性.并且用修饰词Weak修饰的.
接着粘Baby类-----.m文件
```
@implementation Baby
- (void)dealloc
{
NSLog(@"Baby被销毁了");
}
@end
```
说明:该方法的作用是当该类的对象被销毁时会调用-dealloc方法(在这个案例中用来观察对象是否被销毁了)
-
再有介绍BabyServant类-----.m文件
//BabyServant类也就是保姆必须遵循代理协议 @interface BabyServant()<LLBabyDelegate> //并有一个需要照顾的Baby @property(nonatomic, strong) Baby *baby; @end @implementation LLBabyServant //初始化方法 - (instancetype)init { self = [super init]; if (self) { // 初始化'婴儿'对象 self.baby = [[Baby alloc]init]; // 设置'自己(LLBabyServant)'为(Baby)类的代理 self.baby.delegate = self; } return self; }
-
我们介绍最后一个类 ViewController类
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; LLBabyServant *servant = [[LLBabyServant alloc]init]; } @end
说明: 在ViewController的方法ViewDidLoad中创建保姆对象,并且该对象作用的范围是这个方法内部.这个方法执行完成,servant对象就会被销毁了.
上面的代码执行完成之后,运行结果如下:
2016-02-18 15:06:41.151 代理weak案例[1805:173874] LLBabyServant 被销毁了
2016-02-18 15:06:41.152 代理weak案例[1805:173874] Baby类被销毁了
这就说明LLBabyServant对象和Baby对象在没有用处之后都会被销毁,但是如果用代理用strong修饰,而不是用weak修饰,则不会打印上面的结果!
四.分析
1. 用weak分析图如下:
-
整体来看如下图
-
分开来看如下图:
如果weak的话,在程序运行的时候不会造成循环引用,对象都会被顺利的销毁,所以会调用婴儿类和保姆类的delloc方法
2. 用strong分析如下
-
整体来看如下图
-
分开来看如下图
如果strong的话,在程序运行的时候会造成循环引用(意思就是reatainCount不为0,只要有实线引用,计数器就+1),对象都不会 - 的销毁,所以会调用婴儿类和保姆类不会调用delloc方法,从而造成了内存泄露的问题
- 原文链接: https://www.jianshu.com/p/661a01405802
总结: weak 会被 ARC 释放 strong 不会被自动释放
strong vc.delegate=self 引用计数加1
weak 引用计数不加1