Retain Cycle

逻辑电平(TTL/CMOS/LVDS/LVPECL/CML) 逻辑电平介绍 TTL------晶体管-晶体管逻辑门(Transistor-Transistor Logic gate) TTL采用5V电源 阅读详情

在iOS4.0推出了Blocks這個語言特性後,到現在iOS都已經出到5.0了,所以我想Blocks應該可以被廣泛應用了
但現在iOS環境是從MRC(Manual Reference Counting) 走到ARC (Automatic Reference Counting)
在Reference Counting的環境中Runtime是無法自動解除Retain cycle的
而Blocks有很多隱性的retain的動作,很容易不小心的造成retain cycle。
而本篇的重點是點出三種會造成Retain Cycle的Anti-patterns,再來講一下怎麼解決。

在討論之前還是先大概重述一些概念,block當中是允許去使用外部的variable,但是local variable是會自動做retain的動作
例如

MyClass* foo = ….;
self.someBlock = ^
{
    [foo bar];
};

上面的foo在此block被copy到heap的時候,也會一起被自動retain,而這就是我說的很容易造成retain cycle的主因。


Anti Pattern 1
第一個例子我們先用大家很常用的Opne source library ASIHttpRequest當作一個範例
看看下面的例子,有發現任何問題嗎?

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setCompletionBlock:^{
    NSString *responseString = [request responseString];
    NSData *responseData = [request responseData];
}];

這邊我們要首先要注意的點就是[request setCompletionBlock:…]這裡
很明顯的這邊的用途是要做一個event callback的用途,也就是說我給你一個block,當動作完成的時候callback我。這是一個典型的非同步的作法。
但由於如果你要把block拿來之後使用,你一定要呼叫[aBlock copy]的動作,此動作會把block從stack丟進heap。
因為在iOS的環境block也是一個object,此時這個block的retain count就會增加1
這時候根據定義,這個block中參照的request這個local變數就也會被retain起來。
所以request的retain count也會增加1。
但問題來了,一旦request完成任務,應當要被release的時候
卻會發現retain count始終無法歸零。

理由是 request <-> block 這兩個互相 retain 而無法正常釋放,這就是所謂的retain cycle了。


解決方法很簡單,看看ASIHttpRequest官網的文件也就是用__block來描述request

__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setCompletionBlock:^{
    NSString *responseString = [request responseString];
    NSData *responseData = [request responseData];
}];

通過block variable不會retain的特性,有點類似weak reference的作用,此時block就不會retain request
當然也就不會有retain cycle的問題。


Anti Pattern 2
Anti Pattern 1是在使用別人的library的時候容易出現的
Anti Pattern 2是在實作自己的class的時候容易出現
請看下面這段code

//MyClass.h
@property <nonatomic, copy=""> MyBlock onCompleteBlock;

//MyClass.c
self.onCompleteBlock = ^{
    [self doSomething];
}

我相信這邊大家已經馬上看出問題在哪裡了,其實Anti Pattern2算是Anti Pattern 1的特例,只是這邊使用的是特殊變數self

但有些時候我們更容易忽略的是在block中始用自己的member variable
例如

//MyClass.h
@interface MyClass : NSObject
{
    NSDate* lastModifed;
}

//MyClass.c
self.onCompleteBlock = ^{
    lastModifed = [[NSDate date] retain];
}

這時候就沒有那麼容易察覺了。根據定義,在使用block的時候,
如果我們使用到member variable,此時retain的不是lastModified指到的object 而是retain self。
所以造成的就是 self <-> block 互相 retain
跟anti pattern 1一樣的結果就是無法最終釋放記憶體。

這時候的解決方法也是一樣是拿出__block來用

//MyClass.c
__block MyClass* tempSelf = self;
self.onCompleteBlock = ^{
    tempSelf.lastModifed = [NSDate date];
}


Anti Pattern 3

繼續看下面的code

SettingsViewController* settingsViewController = [[[SettingsViewController alloc] init] autorelease];
settingsViewController.onUpdate = ^
{
    [self doUpdate];
}
self.settingsViewController = settingsViewController;


雖然這個Block中沒有直接使用到settingsViewController,感覺應該不會有retain cycle
但是因為 self. settingsViewController 而 settingsViewController.block 再來 block 里 [self doUpdate]
這就剛好繞了一圈,同樣會有retain cycle。

所以呢,還是要想一樣用anti pattern 2的解法去解決

//RootViewController.m
SettingsViewController* settingsViewController = [[[SettingsViewController alloc] init] autorelease];
__block RootViewController* tempSelf = self;
settingsViewController.onUpdate = ^
{
    [tempSelf doUpdate];
}
self.settingsViewController = settingsViewController;

在reference counting的環境裡,我建議要解決retain cycle的最好思維就是想清楚從屬關係
例如最後一個anti pattern 他們的從屬關係應該就是
RootViewController -> SettingsViewController -> block
如果block要用到SettingsViewController或是RootViewController,則就要使用weak reference (也就是__block)
在這樣的原則之下,就可以知道哪些要給他retain哪些不要了。

最後要補充一點就是上面的例子都是在MRC環境下當做範例,在MRC中__block variable在block中使用是不會retain的
但是ARC中__block則是會Retain的。
取而代之的是用__weak或是__unsafe_unretained來更精確的描述weak reference的目的
其中前者只能在iOS5之後可以使用,但是比較好 (該物件release之後,此pointer會自動設成nil)
而後者是ARC的環境下為了相容4.x的解決方案。
所以上面的範例中

__block MyClass* temp = …;    // MRC環境下使用
__weak MyClass* temp = …;    // ARC但只支援iOS5.0以上的版本
__unsafe_retained MyClass* temp = …;  //ARC且可以相容4.x以前的版本

 

在Ubuntu上安装Node.js编程 在Ubuntu操作系统上安装Node.js是非常简单的,本文将为您提供详细的安装步骤。这是一个简单的Node.js HTTP服务器示例,它将在本地主机的端口3000上监听请求,并返回"Hello, World!npm是Node.js的包管理器,您可以使用它来安装和管理Node.js模块。您已成功在Ubuntu上安装了Node.js,并创建并运行了一个简单的Node.js应用程序。现在,您已经成功安装了Node.js和npm,让我们创建一个简单的Node.js应用程序并运行它。如有任何疑问,请随时提问。 阅读详情

相关推荐

ADB详细(从下载安装到灵活运用)

ADB(Android Debug Bridge)是一种允许模拟器或已连接的 Android 设备进行通信的命令行工具,它可为各种设备操作提供便利,如安装和调试应用,并提供对 Unix shell(可用来在模拟器或连接的设备上运行各种命令)的访问。可以在Android SDK/platform-tools中找到 adb 工具或下载ADB Kits。

LiuYong_01的博客 10万+

GeekBand·iOS--Retain Cycle(引用循环)那些事

Retain Cycle:Retain Cycle是如何形成的呢?我们知道当一个父对象(主动方)持有子对象(被动方)时,子对象会随着父对象的消亡而消亡 但是假若两个对象互为父对象呢?会如何? 对,这样子,一个retain cycle就形成了,当然,互为父对象的引用都需要是强引用。 举个简单的例子: 就比如在一般的delegate情况下,一般都是子对象将delegate设为父对象,所以为

dark19940411的专栏 1967

FPGA之道(22)VHDL基本程序框架

在介绍详细的VHDL语法之前,让我们先来了解一下VHDL代码的基本程序框架,这样可以让我们先对VHDL程序设计有一个整体的概念把握,进而在后续的VHDL语法学习中做到有的放矢。

Reborn Lee 8308

IOS内存泄露分析Retain Cycle的解决方法

一个使用Block语法的实例变量,在引用另一个实例变量的时候,经常会引起retain cycle。这个问题在使用ASIHTTPRequest的block语法的时候会时不时的碰到。这个问题困扰了我这个小白很久。终于有一天,在Advanced Mac OS X Programming上,看到了这个问题的解决方案。先用代码描述一下症状:#import typedef void (^ABlock)(void

dlmlzz09的专栏 1229

达梦数据库集群部署(主备)

达梦数据库集群部署(主备)

m0_71845127的博客 1461

STM32通过ESP8266连接机智云APP(第二讲,烧录固件并测试)

今天与大家分享STM32通过ESP8266连接机智云APP,并完成数据的上传下发第二讲。带大家一起烧录机智云固件到ESP8266并且将其通过机智云串口助手与APP进行测试。

qq_63267523的博客 1425

Captureing ‘self’ strongly in this block is likely to lead to a retain cycle Block的Retain Cycle的解决方法

一个使用Block语法的实例变量,在引用另一个实例变量的时候,经常会引起retain cycle。这个问题在使用ASIHTTPRequest的block语法的时候会时不时的碰到。这个问题困扰了我这个小白很久。终于有一天,在Advanced Mac OS X Programming上,看到了这个问题的解决方案。 先用代码描述一下症状: 1 2 3 4 5 6 7 8

hufeng825的专栏 1734

Agentic AI为教育行业赋能,提示工程架构师解析应用潜力

然而,即便是最先进的 LLMs,在面对复杂、动态、需要持续规划和调整的教育场景时,也常常显得力不从心,它们更像是强大的“问答机器”,而非真正意义上的“学习伙伴”或“教学助手”。在教育场景中,传统的 AI 工具可能只能回答学生提出的特定问题,或者根据预设的规则推送一些学习材料。无论您是教育技术领域的开发者、产品经理,还是一线的教育工作者、教育管理者,抑或是对 AI 教育应用充满好奇的研究者,本文都将为您提供宝贵的 insights,助您把握 Agentic AI 时代教育创新的脉搏。

架构师的AI之路,分享AI应用开发架构的学习与实践。 466

iOS blocks - 三個會造成retain cycle的anti patterns

在iOS4.0推出了Blocks這個語言特性後到現在iOS都已經出到5.0了所以我想Blocks應該可以被廣泛應用了但現在iOS環境是從MRC(Manual Reference Counting) 走到ARC (Automatic Reference Counting)在Reference Counting的環境中Runtime是無法自動解除Retain cycle的而Blocks有很多隱性的re...

weixin_33991418的博客 148

AUTOSAR CP R18-10 架构总览与导航

AUTOSAR CP R18-10 架构总览 本文档系统整理了AUTOSAR CP R18-10版本的199篇技术规范,涵盖7大架构层级: 应用层(15篇):包含车身舒适、底盘控制、HMI、安全系统、动力系统等AI应用 RTE(1篇):虚拟功能总线规范 服务层(159篇):细分为系统服务(OS/ECU管理/加密)、存储服务、通信服务(CAN/LIN/Ethernet) ECU抽象层(20篇):I/O与通信硬件抽象 MCAL(41篇):微控制器驱动层 复杂驱动(14篇):CDD设计与SPAL支撑 规范模板(2

一名留德华的,康德的信徒的,专注于汽车电子领域的博客 718

C#项目实战——YModem协议文件传输【实例】

1、先由上位机发送*update*的握手信号,下位机返回响应字符‘C’(字符C,ASII码为0x43),之后通信双方开始以YMODEM协议进行数据通信。2、 YMODEM协议格式说明(1)起始帧数据格式帧类型(1byte)帧序号帧序号反码传输的文件名文件大小数据CRCSOH00FFfilenamefileziseNULCRCSOH=0x01,表示这个数据帧中包含着128个字节的数据(STX表示1024字节,初始帧只有128个);00表示数据帧序号,初始是0,依次向下排。

做有价值的事,积累有价值的笔记! 3654

探讨OC的内存管理 以及防止循环引用retain cycle 代理为什么用weak block为什么用copy

首先声明OC的内存管理机制:引用计数。当一个对象的引用计数为0时,这个对象就会被释放。铭记以上两点,我们开始来探讨。 换句话说,如果一个对象,没有强指针指向,就会被释放。举个很形象的例子,假如每一个对象都是一只狗,每一个强指针都是狗链子,狗链子的数量就是引用计数。那么情况就会变成这样:当一个狗没有被狗链子拴着的时候,它就跑了。哈哈~ 那么什么情况下又会造成循环引用呢?顾名思义,就是两个对象相互强引用

Se7en丶潇洒哥 的博客 2328

Freeswitch DTMF 按键无法接收问题修复

freeswitch 在接收到 update后,会更新成新的 payload type,但是给的200响应,仍然是旧的,这时候就会导致手机侧认识需要发送旧的payload,所以发到 fs 后就会导致直接丢包,不去处理RTP包了。呼叫时需要设置通道变量 rtp_manual_rtp_bugs=ACCEPT_ANY_PAYLOAD ,这时候FS 就不会对包的payload进行判断,直接判定通过。应该修复 freeswitch 给响应时,应该根据收到的 payload 发送给手机,但是一直未找到正确的路径。

2301_81507069的博客 373

警告:Block的Retain Cycle的解决方法

警告:Captureing ‘self’ strongly in this block is likely to lead to a retain cycle 一个使用Block语法的实例变量,在引用另一个实例变量的时候,经常会引起retain cycle。这个问题在使用ASIHTTPRequest的block语法的时候会时不时的碰到。这个问题困扰了我这个小白很久。终于有一天,在Advanc

taylor的专栏 1万+

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

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

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

关于block坑爹的retain Cycle

http://sealedace.com/blog/2014/01/23/block-retain-cycle/ 在进入正题之前,建议读一下船哥的文章——iOS中消息的传递机制。里面除了描述iOS中消息的传递机制,还提供了一些思路帮助大家正确选择某种传递方法来完成开发工作。而本篇文章的主题是跟block相关的。 我们知道在使用block时,必须避免出现retain cycl

fg313071405的专栏 777

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Block的Retain Cycle的解决方法

一个使用Block语法的实例变量,在引用另一个实例变量的时候,经常会引起retain cycle。这个问题在使ASIHTTPRequest的block语法的时候会时不时的碰到。这个问题困扰了我这个小白很久。终于有一天,在Advanced Mac OS X Programming上,看到了这个问题的解决方案。 先用代码描述一下症状: 1 2 3 4 5 6 7 8

SpeedBoy007的专栏 805

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

在使用block过程中,经常会遇到retain cycle的问题

SDWebImage库里的函数: - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(S

andy_jiangbin的专栏 710

Block的Retain Cycle的解决方法 (dealloc不掉用)

一个使用Block语法的实例变量,在引用另一个实例变量的时候,经常会引起retain cycle。这个问题在使用ASIHTTPRequest的block语法的时候会时不时的碰到。这个问题困扰了我这个小白很久。终于有一天,在Advanced Mac OS X Programming上,看到了这个问题的解决方案。 先用代码描述一下症状: 1 2 3 4 5 6 7 8

碧海蓝天的专栏 1755

解决block的retain cycle的警告问题

block retain cycle

青山流云的博客 516

正确使用Block避免Cycle Retain和Crash

http://tanqisen.github.io/blog/2013/04/19/gcd-block-cycle-retain/ 正确使用Block避免Cycle Retain和Crash APR 19TH, 2013 本文只介绍了MRC时的情况,有些细节不适用于ARC。比如MRC下__block不会增加引用计数,但ARC会,AR

sszTechnology的博客 492

capturing self strongly in this block is likely to lead to a retain cycle 警告解决

警告: capturing self strongly in this block is likely to lead to a retain cycle 意思是block会retain一次,所以使用前最好     __block ViewController *strongBlock = self; __block ViewController *strongBlock = s...

九天揽月 1万+

capturing self strongly in this block is likely to lead to a retain cycle

一个使用Block语法的实例变量,在引用另一个实例变量的时候,经常会引起retain cycle。capturing self strongly in this block is likely to lead to a retain cycle_items = [[NSMutableArray alloc] init]; _block = ^{ [_items ad...

jimmychan的博客 2599

RAC 中一个 retain cycle 问题

今天使用 RAC 注册通知时,遇到一个不是很明显的retain cycle问题,使用场景是在一个ViewController中注册一个通知,代码如下: 1 2 3 4 5 6 - (void)viewDidLoad { [super viewDidLoad]; [[[[NSNotificationCenter def...

weixin_34341117的博客 210
上一篇: Choose a destination with a supported architecture in order to run on this device.
下一篇: [UIColor colorWithRed: green: blue: alpha:] 失效问题
一秀
博客等级 码龄14年 1粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值