iOS中assign,copy,retain之间的区别以及weak和strong的区别 代理为啥要用weak修饰

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了,有了上面的只是准备,应该可以理解下面的要解释的东西了.

三.案例说明

  1. 案例介绍
```
    案例中的类介绍: 案例共用到三个类,Baby类(婴儿类),LLBabyServant类(保姆类),ViewControllr类(控制器类),其中说明问题的关键是之前两个类.
    假设,婴儿类要想做一些事情(像换衣服了,方便了之类的...)就必须具有代理的属性,因此指定了一个协议<LLBabyDelegate>,合情合理.而保姆需要成为婴儿的代理,必须遵循协议,废话不多说,上代码!
```
  1. 首先介绍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方法(在这个案例中用来观察对象是否被销毁了)
  1. 再有介绍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;
    }
    
  2. 我们介绍最后一个类 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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值