Short answer

Instead of accessing self directly, you should access it indirectly, from a reference that will not be retained. If you're not using Automatic Reference Counting (ARC), you can do this:

__block MyDataProcessor*dp = self;
self.progressBlock =^(CGFloat percentComplete){[dp.delegate myAPI:dp isProcessingWithProgress:percentComplete];}

The __block keyword marks variables that can be modified inside the block (we're not doing that) but also they are not automatically retained when the block is retained (unless you are using ARC). If you do this, you must be sure that nothing else is going to try to execute the block after the MyDataProcessor instance is released. (Given the structure of your code, that shouldn't be a problem.) Read more about__block.

If you are using ARC, the semantics of __block changes and the reference will be retained, in which case you should declare it __weak instead.

Long answer

Let's say you had code like this:

self.progressBlock =^(CGFloat percentComplete){[self.delegate processingWithProgress:percentComplete];}

The problem here is that self is retaining a reference to the block; meanwhile the block must retain a reference to self in order to fetch its delegate property and send the delegate a method. If everything else in your app releases its reference to this object, its retain count won't be zero (because the block is pointing to it) and the block isn't doing anything wrong (because the object is pointing to it) and so the pair of objects will leak into the heap, occupying memory but forever unreachable without a debugger. Tragic, really.

That case could be easily fixed by doing this instead:

id progressDelegate = self.delegate;
self.progressBlock =^(CGFloat percentComplete){[progressDelegate processingWithProgress:percentComplete];}

In this code, self is retaining the block, the block is retaining the delegate, and there are no cycles (visible from here; the delegate may retain our object but that's out of our hands right now). This code won't risk a leak in the same way, because the value of the delegate property is captured when the block is created, instead of looked up when it executes. A side effect is that, if you change the delegate after this block is created, the block will still send update messages to the old delegate. Whether that is likely to happen or not depends on your application.

Even if you were cool with that behavior, you still can't use that trick in your case:

self.dataProcessor.progress =^(CGFloat percentComplete){[self.delegate myAPI:self isProcessingWithProgress:percentComplete];};

Here you are passing self directly to the delegate in the method call, so you have to get it in there somewhere. If you have control over the definition of the block type, the best thing would be to pass the delegate into the block as a parameter:

self.dataProcessor.progress =^(MyDataProcessor*dp,CGFloat percentComplete){[dp.delegate myAPI:dp isProcessingWithProgress:percentComplete];};

This solution avoids the retain cycle and always calls the current delegate.

If you can't change the block, you could deal with it. The reason a retain cycle is a warning, not an error, is that they don't necessarily spell doom for your application. If MyDataProcessor is able to release the blocks when the operation is complete, before its parent would try to release it, the cycle will be broken and everything will be cleaned up properly. If you could be sure of this, then the right thing to do would be to use a #pragma to suppress the warnings for that block of code. (Or use a per-file compiler flag. But don't disable the warning for the whole project.)

You could also look into using a similar trick above, declaring a reference weak or unretained and using that in the block. For example:

__weak MyDataProcessor*dp = self;// OK for iOS 5 only
__unsafe_unretained MyDataProcessor*dp = self;// OK for iOS 4.x and up
__block MyDataProcessor*dp = self;// OK if you aren't using ARC
self.progressBlock =^(CGFloat percentComplete){[dp.delegate myAPI:dp isProcessingWithProgress:percentComplete];}

All three of the above will give you a reference without retaining the result, though they all behave a little bit differently: __weak will try to zero the reference when the object is released;__unsafe_unretained will leave you with an invalid pointer; __block will actually add another level of indirection and allow you to change the value of the reference from within the block (irrelevant in this case, since dp isn't used anywhere else).

What's best will depend on what code you are able to change and what you cannot. But hopefully this has given you some ideas on how to proceed.

answered Oct 21 '11 at 19:25
benzado
32.1k972100
 
1  
   
Awesome answer! Thanks, I have a much better understanding about what is going on and how this all works. In this case, I have control over everything so I'll re-architect some of the objects as needed. – XJones Oct 21 '11 at 21:18
   
   
Good answer. I've been using __weak myself in an iOS project. It gives you more safety than __block or __unsafe_unretained, but I imagine most people would be calling this in a situation where self is guaranteed to exist. I also like __weak as a keyword because it is more "explicit" about what's being accomplished, whereas the intentions of __block can be ambiguous. –  mikelikespie Nov 2 '11 at 1:15
7  
   
O_O I was just passing by with a slightly different problem, got stuck reading, and now leave this page feeling all knowledgeable and cool. Thanks! –  Orc JMR Dec 19 '12 at 8:07
   
   
@OrcJMR You're welcome! –  benzado Dec 19 '12 at 22:12
   
   
is is correct, that if for some reason on the moment of block execution dp will be released (for example if it was a view controller and it was poped), then line [dp.delegate ... will cause EXC_BADACCESS? – peetonn Jan 30 '13 at 1:50
   

add / show 5 more comments

There’s also the option to suppress the warning when you are positive that the cycle will get broken in the future:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles" self.progressBlock =^(CGFloat percentComplete){[self.delegate processingWithProgress:percentComplete];}#pragma clang diagnostic pop

That way you don’t have to monkey around with __weakself aliasing and explicit ivar prefixing.

answered Feb 14 '12 at 7:51
zoul
46.8k14112201
 
1  
   
Sounds like a very bad practice that takes more than 3 lines of code that can be replaced with __weak id weakSelf = self; –  Andy Sep 3 '13 at 14:05 
1  
   
There’s often a larger block of code that can benefit from the suppressed warnings. –  zoul Sep 3 '13 at 17:56
   

add comment

I believe the solution without ARC also works with ARC, using the __block keyword:

EDIT: Per the Transitioning to ARC Release Notes, an object declared with __block storage is still retained. Use __weak (preferred) or __unsafe_unretained (for backwards compatibility).

// code sample
self.delegate= aDelegate; self.dataProcessor =[[MyDataProcessor alloc] init];// Use this inside blocks
__block id myself = self; self.dataProcessor.progress =^(CGFloat percentComplete){[myself.delegate myAPI:myself isProcessingWithProgress:percentComplete];}; self.dataProcessor.completion =^{[myself.delegate myAPIDidFinish:myself];
myself.dataProcessor = nil;};// start the processor - processing happens asynchronously and the processor is released in the completion block[self.dataProcessor startProcessing];
answered Oct 21 '11 at 19:59
Tony
1,988711
 
   
   
Didn't realize that the __block keyword avoided retaining it's referent. Thanks! I updated my monolithic answer. :-) –  benzado Oct 21 '11 at 21:41
1  
   
According to Apple docs "In manual reference counting mode, __block id x; has the effect of not retaining x. In ARC mode, __block id x; defaults to retaining x (just like all other values)." –  XJones Oct 22 '11 at 2:08 
   
   
@XJones Thanks for the clarification, I've edited my answer. –  Tony Oct 24 '11 at 15:09
   

add comment

For a common solution, I have these define in the precompile header. Avoids capturing and still enables compiler help by avoiding to use id

#defineBlockWeakObject(o) __typeof(o) __weak
#defineBlockWeakSelfBlockWeakObject(self)

Then in code you can do:

BlockWeakSelf weakSelf = self;
self.dataProcessor.completion =^{[weakSelf.delegate myAPIDidFinish:weakSelf];
weakSelf.dataProcessor = nil;};

How do I avoid capturing self in blocks when implementing an API?的更多相关文章

  1. Some good iOS questions

    这里,我列举了一些在Stackoverflow中一些比较好的关于iOS的问题.大部分我列举的问题都是关于Objective C.所有问题中,我比较喜欢“为什么”这一类型的问题. 问题 1. What’ ...

  2. [转]JavaScriptCore and iOS 7

    原文:http://www.bignerdranch.com/blog/javascriptcore-and-ios-7/ As a rule, iOS programmers don't think ...

  3. [转]UIWebView的Javascript运行时对象

    An alternative, that may get you rejected from the app store, is to use WebScriptObject. These APIs ...

  4. 【Orleans开胃菜系列2】连接Connect源码简易分析

    [Orleans开胃菜系列2]连接Connect源码简易分析 /** * prism.js Github theme based on GitHub's theme. * @author Sam Cl ...

  5. C++ Core Guidelines

    C++ Core Guidelines September 9, 2015 Editors: Bjarne Stroustrup Herb Sutter This document is a very ...

  6. x264源代码简单分析:滤波(Filter)部分

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  7. Async Performance: Understanding the Costs of Async and Await

    Stephen Toub Download the Code Sample Asynchronous programming has long been the realm of only the m ...

  8. .NET Best Practices

    Before starting with best practices tobe followed, it is good to have clear understanding of how mem ...

  9. Architecture of a Java Compiler

    Architectural Overview   A modern optimizing compiler can be logically divided into four parts:   Th ...

随机推荐

  1. 【BZOJ】2743: [HEOI2012]采花(树状数组)

    题目 传送门:QWQ 分析 已经凉凉.看错数据范围敲了发莫队........ 和HH的项链差不多,把每种颜色之前的颜色到再之前的颜色这段区间 区间加. 区间加就树状数组特技 代码 #include & ...

  2. IIS Worker Process 遇到了一个问题,需要关闭

    服务器为2003系统,平时都用的好好的,但是最近经常跳出了!IIS Worker Process 遇到问题关闭! 第二个对话框还有个请单击此处的连接 以下文件将包含在这个错误报告中:C:\DOCUME ...

  3. 对Node的优点和缺点提出了自己的看法?

    (优点)因为Node是基于事件驱动和无阻塞的,所以非常适合处理并发请求, 因此构建在Node上的代理服务器相比其他技术实现(如Ruby)的服务器表现要好得多. 此外,与Node代理服务器交互的客户端代 ...

  4. PCI、PCI-x,PCI-E兼容以及他们之间的区别详细图解

    一.PCI PCI接口分为32bit和64bit两种,32bit就是一般台式机使用的普通的pci接口(图一.图三),64bit接口比32bit接口长一些一般只出现在服务器上(图四.图五).32bit和 ...

  5. Springmvc ajax请求400

    转载做记录 传JSON对象 前端 function test () { var param = {username : "yitop"}; $.ajax({ timeout : 2 ...

  6. c++获取lua嵌套table某属性的值

    开发环境:vs2012 lua版本:LuaJIT-2.0.2 lua文件作为配置文件,c++读取这个配置. lua配置结构如下 SceneConfig = { [] = { name =}, [] = ...

  7. Tkinter简易教程

    支持python的常见GUI工具包: Tkinter 使用Tk平台 很容易得到 半标准 wxpython 基于wxWindows.跨平台越来越流行 Python Win 只能在Windows上使用 使 ...

  8. python变量、引用、拷贝之间的关系

    Python中一切皆为对象,不管是集合变量还是数值型or字符串型的变量都是一个引用,都指向对应内存空间中的对象. 简而言之: 变量直接赋值:新变量本身及其内部的元素都与原变量指向相同的内存空间,并且值 ...

  9. 03-24 Winform图表Chart

    图表主要分为以下几个部分: 1.Annotations--图形注解集合, 2.ChartAreas--图表区域集合, 3.Legends--图例集合, 4.Series--图表序列集合(即图表数据对象 ...

  10. Spring技术内幕之Spring Data JPA-自定义Repository实现

    1.自定义Repository方法接口,让接口的实现类来继承这个中间接口而不是Repository接口 package com.data.jpa.dao; import java.io.Seriali ...