OC对象 - Block解决循环引用

【OC】block的实现 Block语法实际上是作为极普通的C语言代码来处理的。通过支持Block的编译器,含有Block语法的源代码转换为一般C语言编译器能够处理的源代码,并作为极为普通的C语言源代码被编译。这只不过是概念的问题,在实际编译时无法转换成我们能够理解的源码,但clang具有转换成我们可读源代码的功能。通过“-rewrite-objc”选项就能将含有block语法的源代码转换为C++的源代码。说是C++,其实尽是使用了struct结构,其本质是C语言的源代码。clang -rewrite-objc 源代码文件名。 阅读详情

OC对象 - Block解决循环引用

前言

本章将会通过一个循环引用案例,分析其原因,以及在ARC、MRC下的解决方案

1. 循环引用示例

ZSXperson类

@interface ZSXPerson : NSObject

@property (nonatomic, assign) int age;
@property (nonatomic, copy) void(^block)(void);

@end


@implementation ZSXPerson

- (void)dealloc {
    NSLog(@"ZSXPerson - %s", __func__);
}

@end

main.m 中初始化ZSXperson对象person,创建person的block,并在block里面访问person.age

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        ZSXPerson *person = [[ZSXPerson alloc] init];
        person.block = ^ {
            NSLog(@"person.age is %d", person.age);
        };
        NSLog(@"---------------");
    }
    return 0;
}

运行:

person不会销毁

1.1 分析

  • 初始化ZSXperson对象person,然后将block赋值给person的block,此时person是强引用block
  • 在block中,访问了person.age,因为访问了局部变量,所以block捕获了person
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 main.m -o main-arm64.cpp

  • 此时block和person的关系,是相互持有的关系

2. 解决思路

之所以叫循环引用,其实就是相互之间的引用关系形成了环

解决方式就是,断开某个引用关系,打破这个环

3. ARC下

3.1 __weak

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        ZSXPerson *person = [[ZSXPerson alloc] init];
        __weak typeof(person) weakPerson = person;
        person.block = ^ {
            NSLog(@"person.age is %d", weakPerson.age);
        };
        NSLog(@"---------------");
    }
    return 0;
}

person正常销毁的

3.2 __unsafe_unretained

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        ZSXPerson *person = [[ZSXPerson alloc] init];
        __unsafe_unretained typeof(person) uuPerson = person;
        person.block = ^ {
            NSLog(@"person.age is %d", uuPerson.age);
        };
        NSLog(@"---------------");
    }
    return 0;
}

使用__unsafe_unretained也可以正常释放

__unsafe_unretained从命名看,unsafe代表不安全,unretained表示不会产生引用。不安全则表现在,当引用的对象销毁时,他不会把指针设置为nil,因此容易有坏指针异常

3.3 __block

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        ZSXPerson *person = [[ZSXPerson alloc] init];
        person.age = 10;
        __block typeof(person) strongPerson = person;
        person.block = ^ {
            NSLog(@"person.age is %d", strongPerson.age);
            strongPerson = nil;
        };
        person.block();
        NSLog(@"---------------");
    }
    return 0;
}


使用__block正常销毁

需要注意的是,使用__block必须调用block。因为使用__block修饰后,在block里面需要置空,如果没有调用block,就没有置空操作,它依然是循环引用状态无法销毁

未调用block:

调用block后:

4. MRC下

MRC不支持__weak
改为MRC

4.1 __unsafe_unretain…

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        ZSXPerson *person = [[ZSXPerson alloc] init];
        person.age = 10;
        __unsafe_unretained typeof(person) weakPerson = person;
        person.block = [^ {
            NSLog(@"person.age is %d", weakPerson.age);
        } copy];
        NSLog(@"---------------");
        [person release];
    }
    return 0;
}

正常销毁

4.1 __block

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        ZSXPerson *person = [[ZSXPerson alloc] init];
        person.age = 10;
        __block typeof(person) weakPerson = person;
        person.block = [^ {
            NSLog(@"person.age is %d", weakPerson.age);
        } copy];
        NSLog(@"---------------");
        [person release];
    }
    return 0;
}

正常销毁

MRC下,block 里面无需将weakPerson设置为nil,也能正常释放。这是因为,MRC下__block不会对person产生强引用(被__block修饰的对象类型,ARC时会retain,MRC时不会retain)

相当于这根线不生效,因此没有形成循环引用

5. 总结

5.1 ARC下

通常使用__weak来解决循环引用。使用__weak修饰的对象销毁后,指针会自动设置为nil。__unsafe_unretained和__block虽然也可以解决环引用问题,但是__unsafe_unretained在修饰的对象销毁后,指针不会自动设置为nil,因此如果还去使用这个对象就会出现异常。__block需要保证 block 有被调用,否则还是会循环引用。

5.2 MRC下

使用__unsafe_unretained或者__block

@oubijiexi

探究Objective-C中的block 本文目录一、`block`的本质二、`block`的变量捕获机制变量捕获机制的猜想验证变量捕获机制猜想三、`block`的三种类型__NSGlobalBlock____NSStackBlock____NSMallocBlock__四、`block`的`copy`操作 本文将通过将OC代码转换为CPP代码的方式来探究Objective-C中block不同情况下的底层数据结构的情况。 一、block的本质 block的本质是一个封装了函数调用以及函数调用环境的OC对象。 以一个最简单的一个block的定义如下: 阅读详情

相关推荐

Objective-C中block循环引用问题详解

主要给大家介绍了关于Objective-C中block循环引用问题的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Objective-C具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

OC底层探索(二十三)Block用法及原理

Block的使用 return_type表示返回的对象/关键字等(可以是void,并省略) blockName表示block的名称 var_type表示参数的类型(可以是void,并省略) varName表示参数名称 return_type表示返回的对象/关键字等(可以是void,并省略) blockName表示block的名称 var_type表示参数的类型(可以是void,并省略) Block声明及定义语法 varName表示参数名称 return_type (^blockNam

正在注销账号的博客 1107

OC基础 Block

什么是Blocks Blocks是C语言的扩充功能。可以概括为:带有自动变量(局部变量)的匿名函数。 所谓的匿名函数,就是没有名字的函数,在C语言中是不允许的。 在计算机科学中,这种概念也称为:“闭包Closure”、“lambda计算”等。 而且一般而言,函数或者方法里是不能又出现一个函数的,但是Blocks作为一种数据类型,是可以的。通常Blocks用于封装代码。因为即便是写在函数体内部,不去调用它,就不会执行。 Blocks的声明 //无参数 无返回值 void (^block1)(void)

乐事派的专栏 2071

告别软件轮询!用STM32G474的COMP比较器实现纳秒级硬件过压保护(CubeMX配置详解)

本文详细介绍了如何利用STM32G474的COMP比较器实现纳秒级硬件过压保护,通过CubeMX配置详解,展示了硬件比较器相比传统软件轮询方案在响应时间、CPU占用和可靠性等方面的显著优势。文章还提供了实战配置流程和优化技巧,帮助工程师快速构建高效的硬件保护系统。

weixin_28683689的博客 351

基于IP2369与STM32的45W双向PD移动电源设计

USB PD(Power Delivery)是一种面向高功率、智能协商的通用快充协议,其核心在于通过BMC编码在CC线上完成供电能力(PDO)动态匹配与电压/电流精准调控。IP2369作为高度集成的PD协议管理芯片,内置PHY、协议引擎与MOSFET驱动,可卸载MCU实时通信压力;而STM32F103系列凭借低功耗STOP模式与丰富外设,成为电源状态管理与用户交互的理想协处理器。该组合显著提升系统鲁棒性与能效比,适用于便携式移动电源、嵌入式备用电源及PD协议教学验证等场景。本文围绕IP2369配置电阻精度、

weixin_42608299的博客 515

OC - Block 详解

1.Block 的使用 Block 是什么? 块,封装了函数调用以及调用环境的 OC 对象, Block 的声明 // 1. @property (nonatomic, copy) void(^myBlock1)(void); // 2.BlockType:类型别名 typedef void(^BlockType)(void); @property (nonatomic, copy) BlockT...

weixin_42350379的博客 1472

从Wi-Fi到蓝牙:手把手教你用Cadence Virtuoso搭建一个2.4GHz锁相环频率综合器(含PFD/CP/VCO模块设计)

本文详细介绍了如何在Cadence Virtuoso中设计一个2.4GHz锁相环频率综合器(PLL),涵盖从系统架构到模块级设计的全流程。重点解析了PFD、CP和VCO等核心模块的设计技巧与仿真验证方法,帮助模拟集成电路设计师掌握高频PLL的实现要点,满足Wi-Fi和蓝牙等无线通信标准的要求。

weixin_30315723的博客 417

OC和Swift中循环引用的问题

总结一下自己对OC中和Swift中循环引用的认识。 一.OC中的循环引用分为类中的循环引用和对象之间的循环引用。 1.类的循环引用 造成原因: 在两个类的.h文件中使用了#import "" 而造成两个类之间的循环引用 解决办法:在一个类的.h中使用#import "",而在另外一个类中使用@class ; 2.对象之间的循环引用:即两个类的实例进行了相互指向, 如: // 教

WJ的博客 1313

别再搞混了!MATLAB通信仿真中EbN0转SNR的保姆级公式推导与避坑指南

本文深入解析MATLAB通信仿真中EbN0与SNR转换的核心公式,揭示数字仿真与理论系统的关键差异。通过真实案例展示错误参数设置导致的隐蔽问题,并提供完整的参数自查清单和正确实现代码,帮助工程师和学生避免常见错误,确保仿真结果准确可靠。

weixin_28746223的博客 348

ERROR: Could not install packages due to an OSError: [Errno 2] No such file or directory解决方案

本文主要介绍了ERROR: Could not install packages due to an OSError: [Errno 2] No such file or directory解决方案,希望能对使用Python的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 11万+

block本质探寻八之循环引用

说明:阅读本文,请参照之前的block文章加以理解; 一、循环引用的本质 //代码——ARC环境 void test1() { Person *per = [[Person alloc] init]; per.age = 10; per.block = ^{ NSLog(@"-------1"); }; } ...

aqqf36217的博客 196

【BUG已解决】pip install 出现 error: Microsoft Visual C++ 14.0 or greater is required 解决方案

方案磁盘占用适用场景推荐指数安装Build Tools3-6GB长期Windows Python开发⭐⭐⭐⭐⭐寻找预编译wheel无额外占用只是想快速装上某个包⭐⭐⭐⭐⭐用conda安装视包而定已经在用conda环境⭐⭐⭐⭐⭐升级到新版本无额外占用库本身有更新的预编译版本⭐⭐⭐⭐使用WSL2需要额外配置Linux子系统频繁遇到Windows编译问题⭐⭐⭐⭐的核心是Windows 缺少本地 C/C++ 编译器,而目标包需要在本机编译。先看是否有捷径。

博客 1万+

Block 阅读笔记

https://www.jianshu.com/p/25a7ba546eac https://www.jianshu.com/p/4e79e9a0dd82 看了"小胖白兔"的两篇关于Block的文章,感觉获益良多。 再次总结一下阅读笔记,便于自己查看 1、Block是什么 Block本质上也是一个OC对象,是封装了函数调用以及函数调用上下文环境的OC对象 2、Block有哪几种 Block的类型...

阿飞小伙子_博客 312

南方电网专业面试题(电气类-继电保护)(目录)

南方电网专业面试题(电气类-继电保护)(目录) 这些面试题围绕继电保护的基本概念、工作原理、分类、性能要求,以及变压器、断路器、母线保护、自动重合闸等电力系统关键设备的保护机制和操作原则展开,旨在评估应聘者对电力系统保护和控制策略的深入理解和实际应用能力。

weixin_44808274的博客 2158

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

OC内存泄漏

1. 内存泄漏的定义 程序中已动态分配的堆内存因为某种原因程序未被释放或者无法释放,造成内存浪费,导致程序运行缓慢或者崩溃等严重后果。 2. OC中内存泄漏的几种情况和解决办法 2.1 对象间的循环引用 2.1.1 普通对象的循环引用 解决方法是将对象之间引用环的某一强引用(strong)改为弱引用(weak)。 // ClassA @property (nonatomic, weak) ClassA * a; // ClassB @property (nonatomic, strong) ClassB

lxh_____的博客 626

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

iOS进阶 - Block底层原理

iOS进阶 - Block底层原理 一 block的本质 1 block本质上也是一个oc对象,它内部也有一个isa指针 2 block是封装了函数调用以及函数调用环境的oc对象 3 block的底层结构 Block源码转换查看 block在实际编译时无法转换成我们能够理解的源代码,但可以通过clang(LLVM编译器)转换成可读的源代码,步骤如下: 1打开终端,输入cd 把要转换的文件拖到终端,然后回车进入要转换文件的目录; 2输入命令clang -rewrite-objc main.m -o main.

qq_20461469的博客 314

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

iOS 内存泄漏的几种原因

1、对象循环引用 @class ,Strong,weak 2、block循环引用 __weak typeof(self) weakself = self; 3、NSNotification的观察者忘记移除 [[NSNotificationCenter defaultCenter] removeObserver:self]; 4、delegate循环引用问题 @property (nonatomic...

heqiang2015的博客 4285

oc 协议 回调 静态成员_OC底层原理探究:Category、关联对象和block本质

1.分类Category的使用// 给MJPerson类添加分类 @interface MJPerson : NSObject - (void)run; @end @implementation MJPerson - (void)abc{} - (void)run{NSLog(@"MJPerson - run");} + (void)run2{} @end // MJPerson的分类,给M...

weixin_39571179的博客 109

iOS Block 底层结构与变量捕获原理深度解析

本文深入解析iOS开发中Block的底层实现原理。Block本质上是带有自动变量的匿名函数,编译后会被转换为包含函数指针、捕获变量和描述信息的结构体。通过Clang转换工具可查看其C++实现代码,核心结构包括__block_impl基础结构和具体Block实现。Block分为三种类型:全局Block(不捕获变量)、栈Block(捕获变量但未copy)和堆Block(栈Block调用copy后)。在ARC环境下,作为返回值、被强引用或作为API参数等情况会自动触发栈Block到堆Block的拷贝。理解这些机制

Sheffi 1447

iOS Block的深入理解

前言 Blocks是C语言的扩充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了这个新功能“Blocks”。从那开始,Block就出现在iOS和Mac系统各个API中,并被大家广泛使用。一句话来形容Blocks,带有自动变量(局部变量)的匿名函数。 Block在OC中的实现如下: struct Block_layout { void *isa;...

iOS-阳哥 788

关于iOS内存泄漏,还有哪些是你不知道的?

对于iOS开发者,网络请求类AFNetWorking是再熟悉不过了,对于AFNetWorking的使用我们通常会对通用参数、网址环境切换、网络状态监测、请求错误信息等进行封装。在封装网络请求类时需注意的是需要将请求队列管理者AFHTTPSessionManager声明为单例创建形式。对于该问题,AFNetWorking的作者在gitHub上也指出建议使用者在相同配置下保证AFHTTPSessionManager只有一个,进行全局管理,因此我们可以通过单例形式进行解决

u012371575的博客 341

iOS 内存泄漏

我们都知道只要发生循环引用,就在造成内存泄漏,但导致内存泄漏还有很多种情况,且听我述来 文章目录1.block的循环引用1.1 手写的block1.2第三方库的block1.2.1 AFN的AFHTTPSessionManager1.2.2 MJRefresh内需使用weakself2.delegate的循环引用3.非OC对象的内存泄漏4.NSTimer 1.block的循环引用 1.1 手写的b...

GEEK_JACK的博客 713

内存泄漏以及内存排查技术分享

内存泄漏 区分两个基本概念: ·内存泄漏(memory leak):是指申请的内存空间使用完毕之后未回收。 一次内存泄露危害可以忽略,但若一直泄漏,无论有多少内存,迟早都会被占用光,最终导致程序crash。(因此,开发中我们要尽量避免内存泄漏的出现) ·内存溢出(out of memory):是指程序在申请内存时,没有足够的内存空间供其使用。 通俗理解就是内存不够用了,通常在运行大型应...

qq_25303213的博客 3318

【iOS】block

block捕获外部变量时,在。

2402_86720949的博客 453
上一篇: OC对象 - Block内存管理
下一篇: iOS - Runtime-isa详解(位域、union(共用体)、位运算)
aiousee
博客等级 码龄14年 540粉丝 45原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值