iOS经典讲解之Objective-C关联对象的内存管理

Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法PDF Effective Objective-C 2.0:编写高质量iOS与OS X代码的52个有效方法是C++开发大师Scott Meyers亲自担当顾问编辑的“Effective Software Development Series”系列丛书中的新作。从语法、接口与API设计、内存管理、框架等7大方面总结和探讨了Objective-C编程中52个鲜为人知和容易被忽视的特性与陷阱。书中包含大量实用范例代码,为编写易于理解、便于维护、易于扩展和高效的Objective-C应用提供了解决方案。 《Effectiv 阅读详情


@关联对象的内存管理:

如果两个或者两个以上的对象存在关联,那么在内存管理方面要比一个对象的内存管理复杂一些,下面通过一个简单的例子来讲解一下关联对象的内存管理问题:

创建一个Pet(宠物)类:

#import <Foundation/Foundation.h>

@interface Pet : NSObject
{
// 无实例变量</span>
}
// 声明一个行为方法</span>
- (void)play;

@end
#import "Pet.h"

@implementation Pet
// 简单实现
-(void)play
{
    NSLog(@"play......");
}
// 重写dealloc方法,判断对象是否释放
-(void)dealloc
{
    NSLog(@"宠物已经被释放");
    [super dealloc];
}

@end 
然后创建一个Person类,此类的对象可以拥有宠物,从而建立两个对象的关联关系:
#import <Foundation/Foundation.h>
#import "Pet.h"

@interface Person : NSObject
{
// Person对象拥有宠物
Pet *_pet; 
}
// 声明一个方法用来测试
- (void)test;

@end
#import "Person.h"

@implementation Person

// 重写初始化方法
-(instancetype)init
{
    self = [super init];
    if (self) {
// 在初始化对象时创建一只宠物
// 思考:此时的Pet对象在哪释放比较得当
_pet = [[Pet alloc] init];
    }
    
    return self;
}
// 实现测试方法
-(void)test
{
// 在宠物对象已经创建出来的情况下,执行方法
if (_pet) {
        
        [_pet play];
    }
}

// 重写初始化方法 检测Person对象是否被释放
-(void)dealloc
{
    NSLog(@"已经释放");
    [super dealloc];
}
@end

然后创建对象进行测试测试:

// 创建一个Person对象 同时也创建了一个Pet对象
  Person *person = [[Person alloc] init];
  // 执行测试方法
 [person test];
  // 根据内存管理黄金原则 释放对象
 [person release];

此时你运行会发现Person对象已经释放但是Pet对象没有被释放,存在内存问题(内存泄露)

怎么解决哪?如果Person对象释放之后,Pet对象就没有存在的价值了,所以说,在Person对象释放的时候,就应该将Pet对象释放掉,没错,Person对象释放会调用dealloc方法,此时在dealloc方法中将Pet对象释放是最恰当的。

所以在Person类的dealloc方法中添加一句即可,如下:

-(void)dealloc
{ 
   // 添加
   [_pet release];
    NSLog(@"已经释放");
    [super dealloc];
}

情况二 :上面是通过初始化方法直接给Person对象实例变量赋值,如果通过其他方法赋值时比如set方法对其赋值时的内存怎么处理哪,下面通过一个例子来了解一下:

#import <Foundation/Foundation.h>
#import "Pet.h"

@interface Person : NSObject
{
    Pet *_pet;
}
// 声明set方法
- (void)setPet:(Pet *)pet;
- (void)test;
@end 

#import "Person.h"

@implementation Person

// 实现set方法
-(void)setPet:(Pet *)pet
{
// 思考:此时的写法是否存在内存问题?
   _pet = pet;
    
}

-(void)test
{
    if (_pet) {
        [_pet play];
    }
}

-(void)dealloc
{   
    // 当Person对象释放时,将其拥有的宠物释放掉
    [_pet release];
    [super dealloc];
}

@end

通过测试来解决上面思考的问题:

// 创建Person对象
Person *man = [[Person alloc] init];
// 创建Pet对象
Pet *pet = [[Pet alloc] init];
// 通过set方法给Person对象的实例变量赋值
[man setPet:pet];
[man test];
// 根据内存释放原则 释放掉上面alloc出来的对象
[man release];
[pet release];
运行你会发现程序崩溃,原因是什么呢?原因是在Person对象释放时,会释放掉Pet对象,而Pet对象在外面已经释放过一次,就会出现过度释放问题,导致程序崩溃。

解决方法1、(不合理方法)

// 为了不出现重复释放问题,可以在赋值的时候将对象的引用计数加一

// 比如

-(void)setPet:(Pet *)pet

{ _pet = [pet retain];

}

你会发现在测试时,也会出现问题,比如通过set方法对其重新赋值时:

// 创建Person对象        
Person *man = [[Person alloc] init];
// 创建Pet对象
Pet *pet = [[Pet alloc] init];
// 通过set方法给Person对象的实例变量赋值
[man setPet:pet];
 // 创建第二个Pet对象
Pet *pet2 = [[Pet alloc] init];
// 对Person对象实例变量重新赋值

[man setPet:pet2];

 [man test];

// 根据内存释放原则 释放掉上面alloc出来的对象

[man release];

[pet release];
[pet2 release];



此时会出现内存泄露问题,因为retain过两次,而dealloc方法中只释放一次,所以上面解决方法不合理。

解决方法2、(不合理方法)

为了不出现上面内存泄露问题,可以在赋值之前先将原来的释放掉:如

-(void)setPet:(Pet *)pet
{
        [_pet release];
       _pet = [pet retain]; 
    
}
同样会出现问题:

当我们对其赋同样的值时会出现重复操作问题:

如:

// 创建Person对象                 
Person *man = [[Person alloc] init];
// 创建Pet对象
 Pet *pet = [[Pet alloc] init];
// 通过set方法给Person对象的实例变量赋值
 [man setPet:pet];                 
// 对Person对象实例变量再次赋同样的值
[man setPet:pet];
[man test];
// 根据内存释放原则 释放掉上面alloc出来的对象
[man release];
[pet release];     
此时没有必要再release和retain,需要对上面的操作再完善一下:

解决方法3、(合理方法)

-(void)setPet:(Pet *)pet
{
    if (_pet != pet) {
        [_pet release];
        _pet = [pet retain];
    }    
}
这是最完善的操作方法,类似于属性的内存管理。

注意:在实例变量未赋值之前释放是没有问题的,对nil,做release操作相当于对着空气说话,没有任何反应。

iOS 底层探索篇 ——类的加载原理补充,类拓展和关联对象 iOS 底层探索篇 ——类的加载原理补充,类拓展和关联对象1.分类加载是否需要排序2.methodList的数据结构3.主类没有实现load方法,分类实现load方法时的数据加载4.class_ro_t5.类扩展6.关联对象 1.分类加载是否需要排序 由上一篇文章知道,在方法列表中,2个分类的方法的数组指针是在主类之前的,并且数组指针里面是经过排序的。 首先添加2个分类,并且类和2个分类都有一个方法叫做testfunc1。 运行,看到getMethodNoSuper_nolock里面。看到这里是遍历查找。 阅读详情

相关推荐

iOS经典面试题之使用runtime associate方法关联的对象释放及dealloc底层原理

一、题目分析 使用 runtime associate 方法关联的对象,需要在主对象 dealloc 的时候释放吗? 无论在 MRC 下还是 ARC 下均不需要,被关联的对象在生命周期内要比对象本身释放的晚很多,它们会在被 NSObject - dealloc 调用的 object_dispose() 方法中释放。 调用 release :引用计数变为零,对象正在被销毁,生命周期即将结束,不能再有新的 __weak 弱引用,否则将指向 nil,调用 [self dealloc]。 父类调用 dealloc

╰つ栺尖篴夢ゞ 1万+

iOS底层原理班(下)/OC对象/关联对象/多线程/内存管理/性能优化

得遇名师,突飞猛进!iOS培训王者MJ(李明杰)老师精心研发,iOS进阶课程,实用技术不断的更新和升级,更快帮助职场人士在开发领域脱颖而出。远程视频教学,无须长途奔袭,碎片化时间学习,成长随时随地!

iOS关联对象技术底层原理

iOS 通过 runtime 的 API 可以给分类添加属性,关联属性总共有下边3个 API ///获取某个对象的关联属性 id objc_getAssociatedObject(id object, const void *key) { return _object_get_associative_reference(object, (void *)key); } ///给某个对...

大兵布莱恩特 1487

视频教程-iOS底层原理班(下)/OC对象/关联对象/多线程/内存管理/性能优化-iOS

iOS底层原理班(下)/OC对象/关联对象/多线程/内存管理/性能优化 小码...

weixin_30993363的博客 851

Objective-C中文编程入门到精通实战教程

Swift 追求安全与规范,而 Objective-C 则崇尚自由与掌控。它的每一个特性——无论是消息转发、Method Swizzling,还是 Associated Objects——都在告诉你:“你不需要遵守规则,只要你理解后果。但这并不意味着可以随意滥用。正相反,正因为能力强大,才更要谨慎行事。记住几个核心原则:🔹能不用 runtime 黑科技就不用—— 除非你真的需要🔹优先使用 Extension 而非 Category—— 更清晰、更安全。

weixin_30591519的博客 671

3DGS实战避坑指南:从零搭建到成功训练

本文详细介绍了3D Gaussian Splatting(3DGS)从环境配置到成功训练的实战避坑指南。涵盖git clone的正确使用、依赖安装的隐藏陷阱、CUDA版本兼容性解决方案、首次训练验证、常见报错急救方案、性能优化技巧及可视化调试方法,帮助开发者高效搭建和训练3DGS模型。

weixin_29053383的博客 365

【iOS-分类,拓展和关联对象底层探究】

分类是一种在现有类中添加方法的方式。使用分类,可以将一个类的功能分为多个逻辑部分,使得代码更加清晰、易于维护。可以为任意一个类添加方法,包括系统自带的类。创建PersonC和它的分类,在分类实现方法,在本类的对象调用分类也遵循公开和私有方法,分类.h@end分类mNSLog(@"这是PersonC的Category添加的方法");在ViewComtroller调用可以为类添加实例方法和类方法。分类中的方法可以访问原类的所有成员变量和方法。

weixin_61639290的博客 1076

ifix5.8连接ab plc的点-通过rslinx

以ifix连接ab plc的点为例 1.先在rslinx上把plc的点导出为opc server 2.使用opc power tool 作为opc client 去连接 3.保存到项目的PDB文件夹下面,并且以节点名命名。 也可以不以节点名命名,系统自动会生成一个以节点名命名的这种文件,就显得很乱。 同时,项目的PDB目录下面必须还得拷过来一个de...

中国智造2025 4114

【IOS 开发学习总结-OC-24】★★★objective-c——内存管理

【IOS 开发学习总结-OC-24】★★★objective-c——内存管理手动内存管理内存泄露:我们在用面向对象的语言编程时,会不断地创造对象,随着时间的推移,有些老的对象不再会被调用,也不再有指针指向它们,但如果程序没有回收它们占用的内存,就会出现形参内存泄露。有效的内存管理包括2个方面 内存分配(相对容易)——合理设计,尽量减少对象的创建,减少创建过程中对内存的开销 内存回收——程序不再需要该

Albert的专栏 968

RV1126 MIPI CSI-2驱动RGB888图像采集的V4L2实战解析

本文详细解析了在RV1126平台上通过MIPI CSI-2接口采集RGB888格式图像的完整V4L2实战流程。核心内容包括设备树(DTS)配置、内核驱动适配、Media Controller链路调试,以及使用v4l2-ctl工具进行图像抓取与验证的方法,旨在帮助开发者打通从硬件连接到稳定采集RGB888图像数据的关键环节。

weixin_29161719的博客 166

光学薄膜设计入门:Essential Macleod中文版从安装到实战全攻略

本文为光学薄膜设计初学者提供Essential Macleod软件从安装部署到实战应用的全流程中文指南。详细解析了软件核心界面、材料管理及工作流程,并通过一个完整的宽带增透膜设计实例,手把手演示膜系构建、优化与分析方法,帮助用户快速掌握这一业界标杆工具,跨越理论与实操的门槛。

weixin_29309475的博客 985

【Effective Objective-C】内存管理

文章目录前言理解引用计数引用计数工作原理属性存取方法中的内存管理自动释放池保留环要点以ARC简化引用计数 前言 在OC这种面相对象的语言里,内存管理是个重要概念。要想用一门语言写出内存使用效率高而且又没有bug代码,就得掌握其内存管理模型的种种细节。 一旦理解了这些规则,你就会发现,其实OC的内存管理没那么复杂,而且有了“自动引用计数”(Automatic Reference Counting,ARC)之后,就变得更为简单了。ARC几乎把所有内存管理事宜都交由编译器来决定,开发者只需专注于业务逻辑。 理

kochunk1t的博客 1900

避坑指南:微信小程序蓝牙广播在iOS上的那些‘坑’(附serviceUuids传值解决方案)

本文深入解析微信小程序蓝牙广播在iOS平台上的开发难点,特别是`serviceUuids`传值解决方案。通过对比iOS与安卓的蓝牙协议实现差异,提供实战编码策略和硬件端配合方案,帮助开发者有效规避兼容性问题,提升蓝牙外围设备开发效率。

weixin_30316097的博客 423

Effective Objective-C 学习(二)

有时需要在对象中存放相关信息。这时我们通常从对象所属的类中继承一个子类,然后改用这个子类对象。然而并非所有情况下都能这么做,有时候类的实例可能是由某种机制所创建的,而开发者无法令这种机制创建出自己所写的子类实例。Objective-C 中有一项强大的特性可以解决此问题,这就是“关联对象”。

m0_73348697的博客 3276

Centos7搭建OpenStack+创建iaas云主机

主要说明在控制节点和计算节点上,通过脚本的形式,安装OpenStack的iaas安装步骤和创建可运行的云主机。提供实施简单、可大规模扩展、丰富、标准统一的云计算管理平台。

weixin_48218106的博客 1万+

高通SDX55平台:5G速率问题排查分析方法

和大家分享一下高通5G平台5G速率问题排查分析方法。

四儿家的小祖宗的博客 5220

iOS—Effective Objective—C2.0(2)

EOC2

cyberjack的博客 1592

久坐不慌,健康护航 —— 智能震动提醒坐垫的设计与实现

硬件核心:选用 ESP32 为主控,HX711 + 应变片实现精准压力检测,8050 三极管驱动震动马达,锂电池 + TP4056 满足便携供电需求;软件逻辑:核心是 “压力阈值判断 + 时间计时”,达到久坐阈值后触发震动提醒,流程图清晰体现了循环检测、状态重置的核心逻辑;代码特性:代码注释完善,阈值可灵活调整,支持串口调试,新手可直接编译烧录并根据实际场景校准。

weixin_42300449的博客 401

iOS经典讲解之Objective-C属性的内存管理原理

@在进行讲解属性的内存管理之前,先来看看之前我们使用实例变量时是怎样管理内存的: 我们创建两个相关联的类Person类和Pet类,来看看它们中的赋值和取值方法是怎样管理内存的: Pet.h #import @interface Pet : NSObject { NSString *_name; } // 声明赋值 取值方法 - (void)setName:(NSS

刘新林的技术博客 829

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

iOS——内存管理

要想用OC写出内存使用效率高而且又没有 bug 的代码,就得掌握其内存管理模型的种种细节。
一旦理解了这些规则,你就会发现,其实 Objective-C 的内存管理没那么复杂,而且有了"自动引用计数"(Automatic Reference Counting,ARC)之后,就变得更为简单了。ARC 几乎把所有内存管理事宜都交由编译器来决定,开发者只需专注于业务逻辑。 一 理解引用计数 OC语言使用引用计数来管理内存,也就是说,每个对象都有个可以递增或者递减的计数器。如果想使某个对象继续存活,那就增加其引用计

chabuduoxs的博客 1783

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Objective-C综合基础

OC的理解与特性 OC作为一门面向对象的语言,自然具有面向对象的语言特性:封装、继承、多态。它既具有静态语言的特性(如C++),又有动态语言的效率(动态绑定、动态加载等)。总体来讲,OC确实是一门不错的编程语言, Objective-C具有相当多的动态特性,表现为三方面:动态类型(Dynamic typing)、动态绑定(Dynamic binding)和动态加载(Dynam...

seventopalsy的博客 1001

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

iOS关联AssociatedObject一些知识

在我们一个类中如果不希望直接在.m文件添加方法,这样会造成代码量暴涨,我们可以使用分类category去增加方法,但是当我们需要在category中添加属性时候,我们要用到runtime关联去绑定一个属性到我们类对象,现在来看看runtime实现,这里借一张图,我主要介绍下其他文章没有提到的点,当我们在分类设置二个关联对象callback和name- (void)setCallBack:(Call...

weixin_34346099的博客 324

【学习iOS高质量开发】——对象、消息、运行期

public@private@end@public@private@end那么新添加的实例变量就会代替原第一个位置实例变量的偏移量。这样的话,如果代码使用了编译器计算出来的偏移量,那么在修改类定义之后必须重新编译,否则就会出错。例如:某个代码库中的代码使用了一份旧的类定义。如果和其相链接的代码使用了新的类定义,那么运行时就会出现不兼容现象。OC把实例变量当作一种存储偏移量所用的“特殊变量”,交由“类对象”保管。

m0_73974920的博客 1411

Effective Objective-C 2.0(52个有效方法) —— 对象、消息、运行期 读书笔记

用Objective-C等面向对象语言编程时,“对象”就是“基本构造单元”,开发者可以通过对象来存储并传递数据,在对象之间传递数据并执行任务的过程就叫做“消息传递”; 当应用程序运行起来以后,为其提供相关支持的代码叫做“Objective-C运行期环境”,它提供了一些使得对象之间能够传递消息的重要函数,并且包含创建类实例所用的全部逻辑。 6、理解“属性”这一概念 可以用“@propert...

heqiang2015的博客 578

iOS教程:《Effective Objective-C 》技巧篇

  iOS培训在iOS开发中,我们也会使用“类族”(class cluster)这一设计模式,通过“抽象基类”来实例化不同的实体子类。   举例:   + (UIButton *)buttonWit...

congbei8442的博客 148

objective-c启用ARC时的内存管理

在objective-c中,内存的引用计数一直是一个让人比较头疼的问题。尤其是当引用计数涉及到arc、blocks等等的时候。似乎ARC的出现只是让我们解放了双手,由于底层实现依然依赖引用计数,所以开启ARC后,只有对引用计数机制更加了解,才能避免Cycle Retain、Crash等问题的出现。     但是由于使用ARC可以显著提高编码效率,所以建议尽量启用arc,本文内容也将以arc为主,

libragirlwdy的博客 333
上一篇: iOS经典讲解之Objective-C内存管理基础知识及内存管理黄金原则
下一篇: iOS经典讲解之Objective-C属性的内存管理原理
刘新林
博客等级 码龄11年 72粉丝 61原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值