iOS ARC内存管理及强弱指针

2020-05-11  本文已影响0人  天馬

ARC是苹果为了简化程序员对内存的管理,推出的一套内存管理机制,使用ARC机制,对象的申请和释放工作会在运行时,由编译器自动在代码中添加retain和release

1> strong:强指针引用的对象,在生命周期内不会被系统释放,在OC中,对象默认都是强指针

2> weak:弱指针引用的对象,系统会立即释放,弱指针可以指向其他已经被强指针引用的对象

他们都是 arc 的东西

ARC的判断准则:

只要没有强指针指向对象,就会释放对象,弱指针不会这样,及时有弱指针指向对象,对象没有强指针指向,也会自动释放掉。一般,无需显式声明为强指针,但是在封装里,定义方法的时候需要写明。而弱指针,必须显式说明。默认是强指针。

ARC特点

 1> 不允许调用release、retain、retainCount

 2> 允许重写dealloc,但是不允许调用[super dealloc]

 3> @property的参数

  * strong :成员变量是强指针(适用于OC对象类型)

  * weak :成员变量是弱指针(适用于OC对象类型)

  * assign : 适用于非OC对象类型

 4> 以前的retain改为用strong

oc的指针分2种:

1> 强指针:默认情况下,所有的指针都是强指针 __strong

2> 弱指针:__weak

在 点m 文件

#import "Dashuai.h"

@implementation Dashuai

- (void)dealloc

{

    NSLog(@"对象被销毁了!");

    //[super dealloc];

}

@end

在视图控制器

@interface ViewController ()

@property (nonatomic, strong) Dashuai  *da;

@end

@implementation ViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    self.da = [[Dashuai alloc] init];

    NSLog(@"调用了 viewdidlowd 方法!");

}

@end

对象不销毁,da 是强指针对象。

如果是在方法内部,声明的对象(默认都是强指针),那么存在一个声明周期(局部变量)的问题。方法执行完毕,到关括号完毕,内存也就随机自动销毁了。

- (void)viewDidLoad {

    [super viewDidLoad];

    Dashuai *dashuai = [[Dashuai alloc] init];

    NSLog(@"调用了 viewdidlowd 方法!");

}

2016-03-08 17:12:33调用了 viewdidlowd 方法!

2016-03-08 17:12:33对象被销毁了!

如果换__weak,那么语句执行完毕,立即释放内存,加断点课证明

2016-03-08 17:15:41对象被销毁了!

再看控件之间,如图:

视图控制器强引用 view,view 强引用了子控件。

[self.view addSubView];//让 view 对控件强引用

那么这就是以前写代码的时候,连线故事板的控件和代码关联的时候,总是默认weak的原因。因为那是视图控制器在引用子控件,而 view 已经 strong 了,那么视图控制器就没必要 strong。它的内存释放过程是:

如果程序没有必要弄强引用,那么就用若引用,类比是链表,一条龙,视图和姿势图,只一个实线连接(父类对象,强引用子类对象之后),其余的引用用 weak虚线,因为view 已经对子控件强引用了,视图控制器可以不用 strong。这是苹果的应用内存管理机制。当然用 strong 也不是不可以。

还有之前提到的懒加载

控件的懒加载,是手动的写类属性的 set 方法,进行是否已经加载等的判断,避免重复加载的过程。那么手写 set ,在 viewdidload重写代码,就要用 strong 引用,因为是手写代码,那么如果还是 weak ,在 viewdidload 方法里,使用控件对象,那么一旦执行完毕,立即内存被释放,因为是 weak 的。这样在视图加载之前,对象就已经消失了。

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

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

1、强指针:默认情况下,所有的指针都是强指针.我们也可以用__strong修饰。

2、弱指针:用__weak修饰的指针,就是弱指针。

共同点:无论是强指针还是弱指针,都是指针,都可以用来存储地址.都可以通过这个指针访问对象的成员区别:在ARC模式下,他们用来作为回收对象的基准,如果一个对象没有任何类型的强指针指向的时候,对象就会被自动释放。

3、强指针与弱指针的声明默认情况下,所有的指针都是强类型的.也可以用__strong来标识这个指针是强指针,使用__weak标识指针的类型是弱指针类型的指针。

4、ARC模式下对象的回收机制没有强指针指向一个对象的时候.就会被自动回收

5、ARC机制下,属性的类型是OC对象类型的时候,一般用strong,非OC对象的类型使用assign

6、ARC机制下的循环引用问题:当两个类相互引用作为对方的属性的时候.在ARC机制下两边都用strong就会出现循环引用,导致内存泄漏,解决办法:一端用strong,一端用weak

OC-strong和weak指针

ARC简单,不用程序员在去管理内存

1.强指针 Strong

2.弱指针 weak

 <都是对象类型下的>

只要有强指针指向一个对象,那么系统就不会回收该对象

只要没有强指针指向对象,系统“立即”回收该对象

弱指针不会影响对象被回收

默认情况下,所有的指针都是强指针类型

@property(nonatomic,retain)Car * car;

  ARC机制 strong 对象,手动内存管理的retain关键字,(一定能够都是应用在对象类型变量上)

  ARC机制中的 weak 对象手动内存管理的assign关键字,(一定能够都是应用在对象类型变量上)

* @property (nonatomic,strong)Car * car;//强指针类型的对象,会影响对象回收

* @property (nonatomic,weak)Car * car2;// 弱指针类型的对象,不会影响对象的回收

//@property (nonatomic,assign)Car * car3;//造成迷惑,会导致许多程序员搞不清这个变量到底是stong类型的还是weak类型

@property (nonatomic,strong)NSString * name;

@property (nonatomic,strong)NSString * idCard;

//ARC机制下 "基本数据类型"的@property参数使用,与手动内存管理完全一致

@property (nonatomic,assign)int age;//assign仅仅是赋值

下面u附上几附图来比较一下强指针和弱指针

强调一些概念

类:是一种结构,它表示对象的类型,对象引用类来获取和本身有关的各种信息,特别是运行什么代码来处理每种操作。

对象:是一种结构,它包含值和指向其类的隐藏指针。

实例:对象的另一种称呼。

消息:是对象可以执行的操作,用于通知对象去做什么。对象接收消息后,将查询对应的类,以便查找正确的代码来运行。

方法:是为响应消息而运行的代码,根据对象的类,消息可以调用不同的方法。

接口:是对象的类应该提供特殊的特性的描述。

什么是property?

property是一种代码生成机制,能够生成不同类型的getter/setter函数,特别是如果你想要用点(.)操作符号来存取变量的话,你就能必须使用property。

oc中访问成员变量的四种方式

用法如:@property (attribute1,attribute2) float value;这些attribute包括:

readonly  表示这个属性是只读的,就是只生成getter方法,不会生成setter方法。

readwrite 可读可写(默认)设置可访问级别。   

assign:简单赋值,不更改索引计数对基础数据类型(NSInteger)和C数据类型(int ,float,double,char等。  

  copy:建立一个索引数为1的对象,然后释放旧对象retain 到另一个NSString之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1,也就是说,retain是指针拷贝,copy是内容拷贝。在拷贝之前,都会释放旧的对象。 

   nonatomicnonatomic 非原子性访问,不加同步,多线程并发访问会提高性能。注意,如果不加此属性, 则默认是两个访问方法都为原子型事务访问。前两个只是简单的设定变量的可读写性。

@class

1 在Objective-c中,当一个类使用到另一个类,并且在类的头文件中需要创建被引用的指针时,一般有继承关系的用#import;没有继承关系的话,可以在头文件中使用@class,声明类,这样可以提高编译效率。在大型软件中,减少.h文件中的include头文件,提高编译效率是非常重要的。

一种是通过#import方式引入;另一种是通过@class引入

为了简单起见:A类是引用类,B类是被引用类,这里先不考虑A类的实现文件。

#import "B.h"    

@interface A : NSObject {   

    B *b;   

}   

@end  

这两种的方式的区别在于:

1、#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在A.h文件中 B *b 只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息;

2、使用@class方式由于只需要只要被引用类(B类)的名称就可以了,而在实现类由于要用到被引用类中的实体变量和方法,所以需要使用#import来包含被引用类的头文件;

3、通过上面2点也很容易知道在编译效率上,如果有上百个头文件都#import了同一 个文件,或者这些文件依次被#improt(A->B, B->C,C->D…),一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来 讲,使用@class方式就不会出现这种问题了;

4、对于循环依赖关系来说,比方A类引用B类,同时B类也引用A类,需要使用@class,否则会报错。

2@class Dog;//当一个类使用到另一个类时,并且在类的头文件中需要创建被引用的指针时。需要在头文件中引用@class 它类名 如:person类引入dog类对象

3@interfacePerson : NSObject

4@property(nonatomic,strong) Dog *dog;

1#import"Person.h"

2 #import "Dog.h"

3@implementation Person :NSObject

总结一下

@class是放在interface中的,只是为了在interface中引用这个类,把这个类作为一个类型来用的。 在实现这个接口的实现类中,如果需要引用这个类的实体变量或者方法之类的,还是需要import在@class中声明的类进来. 

@property参数详解

1>strong :强指针(适用于oc对象类型)

2>weak  :弱指针(适用于oc对象类型)

3>assign:适用于基本数据类型(即非OC对象类型)

ARC ( iOS 5推出的新功能,全称叫 ARC(Automatic Reference Counting)自动引用计数)

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

    a)在ARC机制中,所有的retain,release都不能再出现,取而代之的则是strong(强指针)和weak(弱指针)

    b)默认情况下,所有的指针都是强指针类型

    c)只要有强指针指向一个对象,那么系统就不会回收该对象;反之,则立即回收该对象

@property中的strong和weak属性

    a)arc中的strong相当于非arc时的retain

    b)arc中的weak相当于非arc时的assign

    c)arc机制情况下不能再出现 [super dealloc];

    d)基本数据类型依然使用assign修饰,对象一般用strong修饰

    e)当arc机制下对象循环依赖时,这时weak就有用处,结合@class。否则都是strong对方会相互拉着对方,释放不了内存

OC中ARC机制中还有内存泄漏吗

基于计数的内存管理是无法处理循环引用的,这和自动不自动没有关系。

另外不管用什么管理方式都解决不了,其实对象已经没用了但是忘了撒手”的bug。

比如即便你没循环引用,但是有一个生存期很长的变量保存着一个根本没用的对象的引用还是会泄露的。基于xcode arc机制 只要不影响程序性能编程并不关心。

参考链接:

https://blog.csdn.net/u011146511/article/details/51527090

https://www.cnblogs.com/wxios/articles/4175468.html

https://www.jianshu.com/p/d8ae167e0cc5

著作权归作者所有。商业转载请联系作者获得授权。

上一篇下一篇

猜你喜欢

热点阅读