Objective-C Blocks Caveat
来源:互联网 发布:安卓网络直播电视软件 编辑:程序博客网 时间:2024/05/16 12:21
http://albertodebortoli.github.io/blog/2013/08/03/objective-c-blocks-caveat/
I like blocks. I really do. It’s been at least two years now I’ve been using them and I still make syntax mistakes, but I like them.
Recently I had a long discussion with my colleagues and friends about the use of self inside blocks. I can hear you saying: “C’mon dude, it’s sooo straightforward and ridiculous!”. I’m sure there are some subtle things to consider about the __weak
and the __strong
qualifiers for self inside blocks.
Preface
As known by humanity, we can refer to self in three different ways inside a block. Here are the three cases:
- using the keyword
self
directly inside the block - declaring a
__weak
reference to self outside the block and referring to the object via this weak reference inside the block - declaring a
__weak
reference to self outside the block and creating a__strong
reference to self using the weak reference inside the block
Well, in this article I’ll try to describe these usages and give my take to them.
Discussion
Case 1: using the keyword self
inside a block
If we use directly the keyword self
inside a block, the object is retained at block declaration time within the block (actually when the block is copied but for sake of simplicity we can forget about it) . A const reference to self has its place inside the block and this affects the reference counting of the object. If the block is used by other classes and/or passed around we may want to retain self as well as all the other objects used by the block since they are needed for the execution of the block.
No big deal. But… what if the block is retained by self in a property (as the following example) and therefore the object (self) is retained by the block?
This is what is well known as a retain cycle and retain cycles usually should be avoided. The warning we receive from CLANG is:
Here comes in the __weak
qualifier.
Case 2: declaring a __weak
reference to self outside the block and use it inside the block
Declaring a __weak
reference to self outside the block and referring to it via this weak reference inside the block avoids retain cycles. This is what we usually want to do if the block is already retained by self in a property.
In this example the block does not retain the object and the object retains the block in a property. Cool. We are sure that we can refer to self safely, at worst, it is nilled out by someone. The question is: how is it possible for self to be “destroyed” (deallocated) within the scope of a block?
Consider the case of a block being copied from an object to another (let’s say myController) as a result of the assignment of a property. The former object is then released before the copied block has had a chance to execute.
The next step is interesting.
Case 3: declaring a __weak
reference to self outside the block and use a __strong
reference inside the block
You may think, at first, this is a trick to use self inside the block avoiding the retain cycle warning. This is not the case. The reference to self is created at block execution time while using self in the block is evaluated at block declaration time, thus retaining the object.
Apple documentation says that “For non-trivial cycles, however, you should use” this approach:
What is the meaning of “trivial block” for Apple? It is my understanding that a trivial block is a block that is not passed around, it’s used within a well defined and controlled scope and therefore the usage of the weak qualifier is just to avoid a retain cycle. On the other hand the meaning of “non-trivial block” is a block where the weak reference is used more than once.
As said at the beginning of this article, I made a lot of researches online, checked some books (Effective Objective-C 2.0 by Matt Galloway and Pro Multithreading and Memory Management for iOS and OS X by Kazuki Sakamoto & Tomohiko Furumoto) and discussions with some developers and I came up realizing that the real benefit of using the strong reference inside of a block is to be robust to preemption. I’ll explain this going through the cases I figured out when it is possible for self to ‘disappear’ (i.e. to be deallocated) during the execution of a block:
Explanation
Case 1: using the keyword self
inside a block:
If the block is retained by a property, a retain cycle is created between self and the block and both objects can’t be destroyed anymore. If the block is passed around and copied by others, self is retained for each copy.
Case 2: declaring a __weak
reference to self outside the block and use it inside the block:
There is no retain cycle and no matter if the block is retained or not by a property. If the block is passed around and copied by others, when executed, weakSelf can have been turned nil. The execution of the block can be preempted and different subsequent evaluations of the weakSelf pointer can lead to different values (i.e. weakSelf can become nil at a certain evaluation).
Case 3: declaring a __weak
reference to self outside the block and use a __strong
reference inside the block:
There is no retain cycle and, again, no matter if the block is retained or not by a property. If the block is passed around and copied by others, when executed, weakSelf can have been turned nil. When the strong reference is assigned and it is not nil, we are sure that the object is retained for the entire execution of the block if preemption occurs and therefore subsequent evaluations of strongSelf will be consistent and will lead to the same value since the object is now retained. If strongSelf evaluates to nil usually the execution is returned since the block cannot execute properly.
Andrea Giavatto showed me also that in an ARC-based environment, the compiler itself alerts us with an error if trying to access an instance variable using the ->
notation. The error is very clear and leaves no room for doubt:
It can be shown with the following code:
TL;TR
Case 1 should be used only when the block is not assigned to a property, otherwise it will lead to a retain cycle.
Case 2 should be used when the block is assigned to a property and self is referenced only once and the block has a single statement.
Case 3 should be used when the block is assigned to a property and self is referenced more the once and the block has more than a statement.
I really have to thank all my colleagues at EF and especially Andrea Giavatto andMatteo Gobbi for the time spent talking about this topic and for reviewing this article. Great developers indeed :)
- Objective-C Blocks Caveat
- Objective-C Blocks
- Objective-C Blocks学习
- Objective-C Blocks学习
- Objective-C Blocks研究
- Objective-C Blocks Quiz
- Objective-C的blocks语法
- Recursive Blocks in Objective-C
- Delayed Blocks in Objective-C
- objective c 中的Blocks语法
- Objective-C Blocks 小测验
- objective-c+中代码块(blocks)
- objective-c 中代码块(blocks)
- objective-c+中代码块(blocks)
- objective-c 中代码块(blocks)
- 谈Objective-C Blocks的实现 (转载)
- Objective-C Blocks测试题与解析
- 初探Objective-c 4:OC中的Blocks
- 栈栈栈栈栈栈栈栈栈栈栈栈栈栈栈栈栈栈栈栈栈栈栈栈栈栈栈
- 范式学习
- 链表222222222222222
- Eclipse或者MyEclipse—在Eclipse或MyEclipse中的操作(3)
- 【Ogre引擎架构】 第十讲 唯美场景-天空盒SkyBox
- Objective-C Blocks Caveat
- MySQL和SQL入门(1-5)
- MyEclipse或Eclipse中工程的导入和导出
- 将GPS点导入ArcGIS并转换为shp图层文件
- 程序员必备工具推荐(技术社区、书籍、平台工具等)
- Spark容错机制
- setValue和setObject的区别
- ajax属性(总忘记录一下)
- centos6.5下安装mysql