iOS ARC内存管理/strong weak copy assign 的用法与区别(一)

copy和mutablecopy的解释:https://www.jianshu.com/p/d01429a4b5c0

 

copy与mutableCopy区别,strong和copy的使用:https://www.jianshu.com/p/c39ffd45bc7f(注意:用copy还是strong修饰一个属性时,与深拷贝浅拷贝不要混为一谈了,是两码事),copy修饰可变类型会变为不可变的,所以要用strong修饰可变类型。

字符串使用copy和strong的区别:https://blog.csdn.net/weweco/article/details/47107277、https://www.cnblogs.com/lidaxia/p/4753514.html

block为什么使用strong:https://blog.csdn.net/shihuboke/article/details/77921287

block使用了外部变量,这种情况也正式我们平时所常用的方式,Block的内存地址显示在栈区,栈区的特点就是创建的对象随时可能被销毁,一旦被销毁后续再次调用空对象就可能会造成程序崩溃,在对block进行copy后,block存放在堆区.所以在使用Block属性时使用Copy修饰,而在ARC模式下,系统也会默认对Block进行copy操作



 

原则:

  • 改源对象的属性和行为,不会影响副本对象
  • 修改副本对象的属性和行为,不会影响源对象

 

ARC是OC编译器的特性,而不是运行时特性或垃圾回收机制;ARC所做的就是在代码编译时为你在合适的位置插入release或者autorelease

ARC的判断准则:只要没有强指针指向对象,对象就会被释放;

 

 

 

 

野指针:指向不确定地址的指针变量。(即没有初始化)使用野指针易因内存泄露出现段错误。而造成内存泄露的原因有两个:

1.访问了没有权限的内存(平时我们正确使用指针的时候,系统应经将相应的内存分配给用户,但是如果指向没有分配的内存,系统会判定我们没有权限)

2.访问了已经释放了的内存。

 

 

做到以下几点可以有效地避免野指针的出现。

 

第一,当一个指针没有指向时,我们一般默认指向NULL。(NULL代表内存的0地址,并且NULL是不允许做任何操作的)

 

第二,使用malloc分配内存。(在堆空间里分配内存)

#difine  MAX_SIZE  1024;

char *ptr = (char *) maollc  (sizeof (char) * MAX_SIZE);

 

 

 

 

 

 

所谓的内存泄露就是本应该释放的对象,在其生命周期结束之后依旧存在。

 

 

 

 

强指针:与一般意义的智能指针概念相同,通过引用计数来记录有多少使用者在使用一个对象,如果所有使用者都放弃了对该对象的引用,则该对象将被自动销毁。

弱指针:指向一个对象,但是弱指针仅仅记录该对象的地址,不能通过弱指针来访问该对象,也就是说不能通过弱指针来调用对象的成员函数或访问对象的成员变量。

 

strong:强指针引用的对象,在生命周期内不会被系统释放,作用域销毁时才销毁引用;
    在OC中,对象默认都是强指针,
 weak:弱指针引用的对象,系统会立即释放
    弱指针可以指向其他已经被强指针引用的对象

 

 

 

在MRC模式下:

retain:引用计数加一,是指针拷贝,浅拷贝,在ARC中用strong代替.

assign : 修饰对象时,在ARC中用weak代替;修饰基本数据类型时和ARC中一样;

copy:和ARC中一样,一般用于NSString.

 

++++++++++++++++++++++++++++++++++++++++++++

原则:在ARC模式下,只要没有强指针指向对象,对象就会被销毁.

assign:不会使引用计数加一;

assign:一般用于基本数据类型,指针指向的地址一旦被释放,这些指针不会自动置为 nil。容易产生野指针.

=================================

weak:不会使引用计数加一;

weak:声明为weak的指针,指针指向的地址一旦被释放,这些指针都将被赋值为 nil。这样的好处能有效的防止野指针。

 

assign 指向的对象如果被释放,栈地址不会有任何的变化

  weak 指向的对象如果被释放,地址会立即变化为nil

 

=======================================

Block属性的声明,首先需要用copy修饰符,因为只有copy后的Block才会在堆中,栈中的Block的生命周期是和栈绑定的,如果不加copy修饰,当其所在栈被释放的时候,这些本地变量将变得不可访问。一旦代码执行到block这段就会导致bad access.

使用retain也可以,但是block的retain行为默认是用copy的行为实现的,因为block变量默认是声明为栈变量的,为了能够在block的声明域外使用,所以要把block拷贝(copy)到堆,所以说为了block属性声明和实际的操作一致,最好声明为copy。

 

使用assign: 对基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float, double, char, 等等) 

使用copy: 对NSString ,block

使用retain: 对其他NSObject和其子类 

nonatomic关键字: 

atomic(原子性)是Objc使用的一种线程保护技术(安全的),基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。

strong:对象类型

weak:对象类型,delegate

 

 

 

 

从storyboard中拖出来的控件,OC对象,delegate,一般都用weak.

 

Delegate为啥一般用weak修饰:

 

你的viewcontroller通过strong指针拥有一个UITableview,tableview的datasource和delegate都是weak指针,指向viewcontroller,防止回环,循环引用; 

 

 

 

 

 

=================

copy:也是强引用,持有对象,引用计数器会加一,此属性只对那些实行了NSCopying协议的对象类型有效

copy:一个不可变的对象,copy后没有重新分配内存空间,这是浅拷贝,只拷贝了地址,并没有分配新的内存空间,源对象的引用计数加一,副本对象指向源对象,引用计数也加一.

一个可变的对象,mutableCopy后重新分配内存空间,这是深拷贝(拷贝内容),源对象引用计数不变,副本对象的引用计数加一.

自定义对象的拷贝都是深拷贝.

NSString和block一般都用copy.

对于可变的字符串/数组....是深拷贝,创建出新对象,指针与源对象不同;

 

对于不可变的字符串/数组.....是潜拷贝,不创建出新对象,指针与源对象相同;

 

对于NSString使用copy和strong的区别:

@interface TestStringClass ()

@property (nonatomic, strong) NSString *strongString;

@property (nonatomic, copy) NSString *copyedString;

@end

上面的代码声明了两个字符串属性,其中一个内存特性是strong,一个是copy。下面我们来看看它们的区别。

首先,我们用一个不可变字符串来为这两个属性赋值,

1

2

3

4

5

6

7

8

- (void)test {

    NSString *string = [NSString stringWithFormat:@"abc"];

    self.strongString = string;

    self.copyedString = string;

    NSLog(@"origin string: %p, %p", string, &string);

    NSLog(@"strong string: %p, %p", _strongString, &_strongString);

    NSLog(@"copy string: %p, %p", _copyedString, &_copyedString);

}

其输出结果是:

1

2

3

origin string: 0x7fe441592e20, 0x7fff57519a48

strong string: 0x7fe441592e20, 0x7fe44159e1f8

copy string: 0x7fe441592e20, 0x7fe44159e200

我们要以看到,这种情况下,不管是strong还是copy属性的对象,其指向的地址都是同一个,即为string指向的地址。如果我们换作MRC环境,打印string的引用计数的话,会看到其引用计数值是3,即strong操作和copy操作都使原字符串对象的引用计数值加了1。

接下来,我们把string由不可变改为可变对象,看看会是什么结果。即将下面这一句

1

NSString *string = [NSString stringWithFormat:@"abc"];

改成:

1

NSMutableString *string = [NSMutableString stringWithFormat:@"abc"];

其输出结果是:

1

2

3

origin string: 0x7ff5f2e33c90, 0x7fff59937a48

strong string: 0x7ff5f2e33c90, 0x7ff5f2e2aec8

copy string: 0x7ff5f2e2aee0, 0x7ff5f2e2aed0

可以发现,此时copy属性字符串已不再指向string字符串对象,而是深拷贝了string字符串,并让_copyedString对象指向这个字符串。在MRC环境下,打印两者的引用计数,可以看到string对象的引用计数是2,而_copyedString对象的引用计数是1。

此时,我们如果去修改string字符串的话,可以看到:因为_strongString与string是指向同一对象,所以_strongString的值也会跟随着改变(需要注意的是,此时_strongString的类型实际上是NSMutableString,而不是NSString);而_copyedString是指向另一个对象的,所以并不会改变。

结论

由于NSMutableString是NSString的子类,所以一个NSString指针可以指向NSMutableString对象,让我们的strongString指针指向一个可变字符串是OK的。

而上面的例子可以看出,当源字符串是NSString时,由于字符串是不可变的,所以,不管是strong还是copy属性的对象,都是指向源对象,copy操作只是做了次浅拷贝。

当源字符串是NSMutableString时,strong属性只是增加了源字符串的引用计数,而copy属性则是对源字符串做了次深拷贝,产生一个新的对象,且copy属性对象指向这个新的对象。另外需要注意的是,这个copy属性对象的类型始终是NSString,而不是NSMutableString,因此其是不可变的。

 

一般情况下选择copy,选择使用copy的理由是,NSString属性可能被传入一个NSString实例,也可能是一个NSMutableString实例。当传入了一个NSMutableString实例时,字符串的值可能会在背后悄悄变化

===============

strong:强引用,数组,自定义OC 对象(不是从storyboard中拖出来的),一般用strong;

@property (nonatomic,strong)UIView *vv;

 

self.vv=[[UIView alloc]initWithFrame:self.view.frame];//使用strong的话,对象不会被释放,直接给属性赋值,不会有错;

self.vv.backgroundColor=[UIColor redColor];

   [self.view addSubview:self.vv];

 

 

 

 

 

@property (nonatomic,weak)UIView *vv;

self.vv=[[UIViewalloc]initWithFrame:self.view.frame];//用weak的话,对象还没创建就被释放了,所以给被释放的对象赋值,会报错或警告;

换成下面就可以了:

UIView *v=[[UIView alloc]initWithFrame:self.view.frame];

v.backgroundColor=[UIColorredColor];

self.vv=v;

[self.view addSubview:self.vv];

 

 

 

 

 

 

 

===================

arc和mac模式的相互转换:

1.单个ARC文件转换成mrc文件:-fno-objc-arc

2.单个mrc文件转换成ARC文件:edit----------convert---------To Obj-OC

MRC 兼容ARC :mac转换成arc: -f-objc-arc 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值