weakself and strongself
2016-03-29 18:26
597 查看
Why you should start using @weakify and @strongify macros
By Arkadiusz Holko, 31 May 2015I have to admit something. I haven't used @weakify
and @strongify macros in any of my projects yet. A recent discussion in my team at Macoscope and adiscussion
on Twitter started by Peter Steinberger sparked my interest in these macros. Read on to learn what I found out and why I think they're the way to go in most scenarios.
Standard approach of breaking retain cycles
Let's say we have a view controller with a property called model.
We want to have a label's text update when the data inside the model changes. To do that we set up a model:
- (void)setUpModel { Model *model = [Model new]; // this block is called by the model when its underlying data changes model.dataChanged = ^(NSString *title) { self.label.text = title; }; self.model = model; }
With these few innocent lines of code we introduced a retain
cycle. Our view controller retains the model, which in turn retains a block holding the view controller. We can easily break this retain cycle, by introducing new local variables with
__weakand
__strong1 storage
type modifiers:
Model *model = [Model new]; __weak typeof(self) weakSelf = self; model.dataChanged = ^(NSString *title) { __strong typeof(self) strongSelf = weakSelf; strongSelf.label.text = title; }; self.model = model;
This so called weak/strong dance can be found in most Objective-C codebases. It works fine, but it's error prone. When the new features are introduced and the block's definition gets bigger
someone will eventually use
selfwithin it. We won't notice when
it happens — the compiler helps only in the most simple cases. This is a part when weakify and strongify macros come in handy.
weakify and strongify
Original implementation of @weakify and @strongify macros is complex because they accept more than oneparameter. To make the analysis simpler, we'll introduce our own versions, accepting only one parameter each:
#define weakify(var) __weak typeof(var) AHKWeak_##var = var; #define strongify(var) \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wshadow\"") \ __strong typeof(var) var = AHKWeak_##var; \ _Pragma("clang diagnostic pop")
With these macros in-place, our example takes the following form:
Model *model = [Model new]; weakify(self); model.dataChanged = ^(NSString *title) { strongify(self); self.label.text = title; }; self.model = model;
which—with pragmas omitted—translates to:
Model *model = [Model new]; __weak typeof(self) AHKWeak_self = self; model.dataChanged = ^(NSString *title) { __strong typeof(self) self = AHKWeak_self; self.label.text = title; }; self.model = model;
In the block,
selfis
overshadowed by a local variable with the same name. Then,
selfcan
be used safely inside the block, because it references that local variable, which is held strongly, but lives only until the block ends executing. Even the code not written by us can use
selfsafely,
e.g.
NSAssertmacro.
It's still possible to reference the real
self,
by using an ivar. It leads to a warning, though, so it's a mistake that's easy to spot:
Block implicitly retains 'self'; explicitly mention 'self' to indicate this is intended behavior
Now, you may ask: what if I forget to use
strongify?
This is a cool part:
weakifycreates a new local variable, so if it's
not used at all we get a warning:
Unused variable 'AHKWeak_self'
This warning won't help us, if a strongified self is used in more than one block. This can be worked around by introducing a new scope for each block definition, e.g.:
{ weakify(self); model.dataChanged = ^(NSString *title) { strongify(self); self.label.text = title; }; } { weakify(self); model.syncFinished = ^(BOOL success) { strongify(self); [self update]; }; }
It's not pretty, and I would hesitate before doing things this way, but I think it can be useful in some cases.
As you can imagine, if you forget to use
weakify,
but
strongifyis in its place, the compiler shows an error:
Use of undeclared identifier 'AHKWeak_self'
Final thoughts
To sum up: we still have to think about a possibility of retaining self(or
some other object) when creating a new block. That's not something any macro can help us with. However, once weakify and strongify macros are used, any future changes to blocks' definitions are safer than with the standard weak/strong dance.
As for Swift, a similar construct called capture list is embedded
into the language itself.
相关文章推荐
- linux防火墙/selinux
- Jumb
- MAC 乱码设置
- HashMap
- js获取页面加载过程做一个简单的loading
- 数据库范式
- 第五周技术博客~
- java.text.MessageFormat类的学习
- 使用Typescript编写Redux+Reactjs应用程序
- 【BOOM】一款有趣的Javascript动画效果
- ElasticSearch 2 (37) - 信息聚合系列之内存与延时
- Windows环境下QWT安装及配置
- jar5
- 数据流图懂不懂?
- android spanner下拉列表内容居中
- Material Design实战
- mybatis 错误
- 更新至Xcode7.3后 使用__weak 修饰的属性出现unavailable 的问题
- C++虚函数分析[1]--同名函数继承二义性问题
- 非正规写法获取不到tr,td