当前位置: 首页 > news >正文

「iOS」————MRC


MRC

MRC:手动引用计数管理,通过调用 retainreleaseautorelease 等方法来控制对象的生命周期。

对象操作OC方法
生成并且持有对象alloc/new/copy/mutableCopy等方法
持有对象retain方法
释放对象release
废弃对象dealloc

对于内存管理考虑方式有四点:

单个对象:

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

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

    • NSMutableArray* ary = [NSMutableArray array];
      [ary reatin];
      
  • 不再需要自己持有的对象时释放

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

多个对象内存管理思想

  • 一个对象不持有另外一个对象

此时两个实例对象没有关联可以将各自释放掉

  • 一个对象持有另外一个对象

持有的对象需要在set方法中引用计数加一。释放时也需要将持有的对象销毁

- (void)setMyObject:(MyObject*)myObj { // 引用计数器 +1[myObj retain];_myObj = myObj;
}- (void)dealloc {// 人释放了, 那么房间也需要释放[_myObj release];NSLog(@"%s", __func__);[super dealloc];
}
  • 一个对象持有并释放掉一个对象后持有另外一个对象

此时则需要在更换原持有的对象前,释放第一个对象

- (void)setMyObject:(MyObject*)myObj { [_myObj release];// 引用计数器 +1[myObj retain];_myObj = myObj;
}
  • 一个对象持有一个对象并释放该对象后再次持有该对象

此种情况使用上一个getter方法不难发现,我们将那个对象赋值给该对象后该对象对那个对象的引用计数加一,再将那个对象引用计数减一,此时两个对象的引用计数相同,此时再次进行赋值会导致那个对象的引用计数先减一此时为0变成了野指针,此时再对野指针进行retain操作就会报错。

此时就需要在setter方法中判断是否重复赋值,如果是同一个实例对象,就不需要重复进行 release 和 retain。

- (void)setMyObject:(MyObject*)myObj { if (_myObj != myObj) {[_myObj release];// 引用计数器 +1[myObj retain];_myObj = myObj;}
}

@property参数

  • 在成员变量前加上 @property,系统就会自动帮我们生成基本的 setter / getter 方法,但是不会生成内存管理相关的代码。
@property (nonatomic) int val;
  • 如果在 property 后边加上 assign,系统也不会帮我们生成 setter 方法内存管理的代码,仅仅只会生成普通的 getter / setter 方法,默认什么都不写就是 assign
@property(nonatomic, assign) int val;
  • 如果在 property 后边加上 retain,系统就会自动帮我们生成 getter / setter 方法内存管理的代码,但是仍需要我们自己重写 dealloc 方法。
@property(nonatomic, retain)MyObject *myObj;

自动释放池

autorelease 是一种支持引用计数的内存管理方式,主要用于延迟对象的释放,只要给对象发送一条 autorelease 消息,会将对象注册到一个自动释放池中,当自动释放池被销毁时,会对池子里面的所有对象做一次 release 操作。

autorelease方法会返回对象本身,且调用完autorelease方法后,对象的计数器不变。

Person *p = [Person new];
p = [p autorelease];
NSLog(@"count = %lu", [p retainCount]); // 计数还为 1

创建

  • 第一种是使用 NSAutoreleasePool 创建
NSAutoreleasePoo *pool = [[NSAutoreleasePool alloc] init]; //创建自动释放池[pool release];  [pool drain]; //销毁自动释放池
  • 第二种是使用 @autoreleasepool 创建
@autoreleasepool
{ // 开始代表创建自动释放池} // 结束代表销毁自动释放池

使用

需要注意的是对象调用autorelease方法需要在创建autoreleasepool之后否则无法将其注册到autoreleasepool。

NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init];
Person *p = [[[Person alloc] init] autorelease];
[autoreleasePool drain];@autoreleasepool
{ // 创建一个自动释放池Person *p = [[Person new] autorelease];// 将代码写到这里就放入了自动释放池
} // 销毁自动释放池(会给池子中所有对象发送一条 release 消息)//以上两种使用方法相同

自动释放池的嵌套

  • 自动释放池是以栈的形式存在。
  • 由于栈只有一个入口,所以调用 autorelease 会将对象放到栈顶的自动释放池。
@autoreleasepool { // 栈底自动释放池@autoreleasepool {@autoreleasepool { // 栈顶自动释放池Person *p = [[[Person alloc] init] autorelease];}Person *p = [[[Person alloc] init] autorelease];}
}

注意事项

  • 自动释放池中不适宜放占用内存比较大的对象

因为自动释放池是延迟释放机制,只有清空池子时才会将注册到池子的对象销毁,此时如果有多个内存较大的对象就会造成短时间内内存暴涨。

  • 不要把大量循环操作放到同一个 @autoreleasepool 之间,这样会造成内存峰值的上升。如果一定要循环,则这样使用

    // 内存暴涨
    @autoreleasepool {for (int i = 0; i < 99999; ++i) {Person *p = [[[Person alloc] init] autorelease];}
    }
    // 内存不会暴涨,在循环内部创建自动释放池
    for (int i = 0; i < 99999; ++i) {@autoreleasepool {Person *p = [[[Person alloc] init] autorelease];}
    }
    
  • 不要连续调用 autorelease ,也不要调用后又调用release

@autoreleassepool {// 会导致过度释放Person *p = [[[[Person alloc] init] autorelease] autorelease];
}@autoreleasepool {Person *p = [[[Person alloc] init] autorelease];[p release]; //过度释放
}

循环引用

两个对象互相持有对方,A对象的销毁依赖于B,B对象的销毁依赖于A

1.自循环引用
假如有一个对象,内部强持有它的成员变量obj,若此时我们给obj赋值为原对象时,就是自循环引用。

2.相互循环引用
对象A内部强持有obj,对象B内部强持有obj,若此时对象A的obj指向对象B,同时对象B中的obj指向对象A,就是相互引用。

3.多循环引用
假如类中有对象1…对象N,每个对象中都强持有一个obj,若每个对象的obj都指向下个对象,就产生了多循环引用。

http://www.lryc.cn/news/601613.html

相关文章:

  • Flink2.0学习笔记:Stream API 常用转换算子
  • 第十八章:AI的“通感”:揭秘图、文、音的共同语言——CLIP模型
  • 常见认证机制详解
  • Unity FXAA
  • 设计模式(六)创建型:单例模式详解
  • 五、搭建springCloudAlibaba2021.1版本分布式微服务-gateway网关
  • 新手开发 App,容易陷入哪些误区?
  • c++加载qml文件
  • 【学习笔记】DexMimicGen:通过模仿学习实现双臂灵巧操作的自动化数据生成
  • 小白成长之路-Ansible自动化(一)
  • 小白投资理财 - 从换手率和成交量分析股票趋势
  • 【机器学习深度学习】NLP评价指标 BLEU 和 ROUGE
  • 扩展组件(uni-ui)之uni-group
  • Dify 本地化部署深度解析与实战指南
  • C语言自定义数据类型详解(四)——联合体
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现PCB上二维码检测识别(C#代码UI界面版)
  • 2.安装CUDA详细步骤(含安装截图)
  • JavaEE--3.多线程
  • [N1盒子] 斐讯盒子N1 T1通用刷机包(可救砖)
  • [硬件电路-96]:什么是闭环反馈?什么是闭环正反馈控制?什么是闭环负反馈控制?
  • Java面试精进:测试、监控与序列化技术全解析
  • 【模电笔记】—— 波形发生电路(波形振荡器)
  • Redisson的布隆过滤器
  • 安卓打包遇到问题
  • 重温经典,小巧方便的 WinXP 来啦!提供离线驱动
  • net8.0一键创建支持(Kafka)
  • 深度学习在自动驾驶车辆车道检测中的应用
  • 命令行和neovim的git操作软件-lazygit
  • GO语言 go get 下载 下来的包存放在哪里
  • MMAP 机制通俗易懂