【iOS】OC高级编程 iOS多线程与内存管理阅读笔记——自动引用计数

文章目录

什么是自动引用计数

内存管理/引用计数

概要

内存管理的思考方式

自己生成的对象,自己所持有

非自己生成的对象,自己也能持有

不再需要自己持有的对象时释放

无法释放非自己持有的对象


什么是自动引用计数

自动引用计数(ARC,Automatic Reference Counting)是指内存管理中对引用采取自动计数的技术。用苹果官方说明的话说:

在OC中采用ARC机制,让编译器来进行内存管理,在新一代Apple LLVM编译器中设置ARC为有效状态,就无需再键入retain或者release代码。

也就是说,只要满足以下条件,就无需手动输入retain和release代码了:

  • 使用Xcode4.2或以上版本

  • 使用LLVM编译器3.0或以上版本

  • 编译器选项中设置ARC为有效

在以上条件下编译源代码时,编译器将自动进行内存管理。接下来我们先了解一下在ARC之前,程序员是如何手动进行内存管理的

内存管理/引用计数

概要

OC中的内存管理,也就是引用计数,可以用开关房间的灯为例来说明引用计数的机制。

假设办公室里只有一个照明设备,上班进入办公室的人需要照明,所以把灯打开。而对于下班离开的人来说,已经不需要照明了,所以要把灯关掉。但是,并不是每个人都需要进行开关灯的操作的,只要第一个人开了灯,后面的人就不必再开灯了,关灯也必须是最后一个离开的人关灯。所以为了判断办公室里还有多少人,我们就引入一个计数来统计需要照明的人数。

(1)第一个人进来,人数加一,计数从零变成一,因此要开灯

(2)之后每进来一个人,人数就加一

(3)每当有人下班离开,人数就减一

(4)最后一个人离开时,人数减一,计数从一变成零,因此要关灯

在OC中,"对象"就相当于照明设备,"对象的使用环境"就相当于上班进入办公室的人。上班时发出的动作与OC中的对应关系如下表:

OC的内存管理就是基于这个逻辑实现的

内存管理的思考方式

有关于引用计数,正确的思考方式有四条准则:

  • 自己生成的对象,自己所持有

  • 非自己生成的对象,自己也能持有

  • 不再需要自己持有的对象时释放

  • 非自己持有的对象无法释放

这就是引用计数式内存管理的思考方式,而在OC的内存管理中,除了"生成"、"持有"、"释放"三个词以外,还要加上"废弃",这四个词组成了OC内存管理的基本操作

相对应的方法如下表所示:

这些有关内存管理的方法,包含在Cocoa框架中用于OS X、iOS应用开发。Cocoa框架中Foundation框架类库的NSObject类担负内存管理的职责。OC内存管理中的alloc/retain/release/dealoc方法分别指代NSObject类的alloc类方法、retain实例方法、release示例方法和dealloc实例方法

接下来我们详细了解内存管理的思考方式中的各个项目

自己生成的对象,自己所持有

使用以下名称开头的方法名意味着自己生成的对象只有自己持有:

  • alloc

  • new

  • copy

  • mutableCopy

下面写出自己生成并持有对象的源代码,为生成并持有对象,我们使用alloc方法。

objectivec 复制代码
// 自己生成并持有对象
id obj = [[NSobject alloc] init];

使用NSObject的类方法就能自己生成并持有对象,指向生成并持有对象的指针被赋给变量obj。另外,使用new类方法也能生成并持有对象。

copy方法基于NSCopying方法约定,由各类实现的copyWithZone:方法生成并持有对象的副本,mutableCopy也一样,二者区别只在于生成的对象是否可变。这些方法生成的对象,虽然是对象的副本,但也属于"自己生成并持有对象"。

此外,根据上述"使用以下名称开头的方法名",下列名称也意味着自己生成并持有对象

  • allocMyObject

  • newThatObject

  • copyThis

  • mutableCopyYourObject

但以下名称,并不属于同一类别的方法

  • allocate

  • newer

  • copying

  • mutableCopyed

非自己生成的对象,自己也能持有

用上述项目之外的方法(即alloc/new/copy/mutableCopy以外的方法)取得的对象,因为非自己生成并持有,所以自己不是该对象的持有者。

objectivec 复制代码
//取得非自己生成并持有的对象
id obj = [NSMutableArray array];
//取得的对象存在,但自己不持有对象

这段代码中,NSMutableArray类对象被赋给变量obj,但变量obj自己并不持有该对象,使用retain方法可以持有对象

objectivec 复制代码
//取得非自己生成并持有的对象
id obj = [NSMutableArray array];
//取得的对象存在,但自己不持有对象
[obj retain];
//自己持有对象

通过retain方法,可以将对象变为自己所持有的

不再需要自己持有的对象时释放

自己持有的对象,一旦不再需要时,持有者有义务释放该对象,使用release方法

objectivec 复制代码
id obj = [[NSObject alloc] init];
[obj release];
//释放对象
指向对象的指针仍然被保留在变量obj中,貌似能够访问
但对象一经释放绝对不可访问

这样,对象就被release方法释放了,自己生成而非自己持有的对象,如果用retain变成自己持有,同样可以用release释放

用alloc/new/copy/mutableCopy方法生成并持有的对象,或者用retain方法持有的对象,一旦不再需要,务必用release释放。

如果要用某个方法生成对象,并将其返还给该方法调用方,源代码如下:

objectivec 复制代码
- (id)allocObject {
  id obj = [[NSObject alloc] init];
  return obj;
}

如上例,将用alloc方法生成的对象直接返回。就能让调用方也持有该对象。

注意,这里与上文命名规则相符合,使用allocObject也就意味着"自己生成并持有对象"

那像[NSMutableArray array]这种方法使取得的对象存在,但自己不持有对象,又是如何实现的呢?根据上文规则,不能使用alloc/new/copy/mutableCopy开头的方法名,因此我们使用object这个方法名

objectivec 复制代码
- (id)object {
id obj = [[NSObject alloc] init];
[obj autorelease];
//取得对象存在,但自己不持有对象
return obj;
}

上例中,我们使用了autorelease方法,用这个方法可以使取得的对象存在,但自己不持有对象,autorelease提供这种功能,是对象在超出指定生存范围时能自动并正确的释放。

使用NSMutableArray类的array类方法可以取得谁都不持有的对象,这些方法都是通过autorelease来实现的。

无法释放非自己持有的对象

得到非自己持有的对象无法释放,倘若在应用程序中释放了非自己持有的对象就会造成崩溃。例如自己生成并持有对象后,在释放完不再需要的对象之后再次释放

objectivec 复制代码
id obj = [[NSObject alloc] init];
[obj release];
[obj release];
//应用程序崩溃!
//访问已经废弃的对象时崩溃

或者"取得的对象存在,但自己不持有对象"时释放

objectivec 复制代码
id obj1 = [obj0 object];
//取得对象存在,但自己不持有
[obj1 release];
//程序崩溃

以上就是"引用计数式内存管理"的思考方式

相关推荐
想进大厂的Leo15 分钟前
【LLM学习之路】9月22日 第九天 自然语言处理
人工智能·学习·自然语言处理
CrazyZ1261 小时前
C++第九章编程练习答案
开发语言·c++·笔记·学习·算法
蟹屋在海边2 小时前
iOS 中 KVC 与 KVO 底层原理
ios
不会敲代码的VanGogh2 小时前
【iOS】——JSONModel源码
开发语言·学习·ios·objective-c
留待舞人归2 小时前
【Unity杂谈】iOS 18中文字体显示问题的调查
游戏·unity·ios·游戏引擎·unity3d
Magnetic_h2 小时前
【iOS】KVC
笔记·学习·macos·ios·objective-c·cocoa
岑梓铭2 小时前
考研408《操作系统》复习笔记,第一章《概述》
笔记·操作系统·408·计算机考研
CXDNW2 小时前
【Linux篇】网络编程基础(笔记)
linux·服务器·网络·c++·笔记·网络编程
蜡笔小新星2 小时前
网络安全:构建数字世界的坚实防线
服务器·网络·经验分享·学习·安全·web安全
Q186000000002 小时前
安装MySQL驱动程序笔记一
数据库·笔记·mysql