ReactiveCocoa Weak-Strong Dance

AC在应用中大量使用了block,由于Objective-C语言的内存管理是基于引用计数的,为了避免循环引用问题,在block中如果要引用self,需要使用@weakify(self)和@strongify(self)来避免强引用。

一、block的循环引用问题

?

[objc] view plain copy

print?

  1. - (void)loadView
  2. {
  3. [superloadView];
  4. _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
  5. object:nil
  6. queue:nil
  7. usingBlock:^(NSNotification *note) {
  8. [self dismissModalViewControllerAnimated:YES];
  9. }];
  10. }
  11. - (void)dealloc
  12. {
  13. [[NSNotificationCenter defaultCenter] removeObserver:_observer];
  14. }

代码分析:

在上面代码中,我们添加向通知中心注册了一个观察者,然后在 dealloc 时解除该注册,一切看起来正常。但这里有两个问题:

这段代码中涉及到的对象包括:notificationcenter, _observer, block, self.

a) 在消息通知 block 中引用到了 self,所以这里 self 对象被 block retain;而 _observer 又对该 block 进行retain,通知中心 notificationcentre 又持有 _observer。因此只要 _observer 对象还没有被解除注册,block 就会一直被持有,从而 self 就不会被释放,那么 dealloc 就不会被调用。而我们却又期望在 dealloc 中通过 removeObserver 来解除注册以消除通知中心 notificationcenter 对 _observer 的 retain。

小结:notificationcenter --> _observer --> block --> self 只有在 self 释放,dealloc 调用的时候,notificationcenter 才会释放 _observer,显然其中存在循环引用。

b) 同时,_observer 是在 self 所在类中定义赋值,因此是被 self retain 的,这样就形成了循环引用。

小结: self --> _observer --> block --> self 显然这也是一个循环引用。

二、Weak-Strong Dance

对于在block中的retain cycle,在2011 WWDC Session #322 (Objective-C Advancements in Depth)有一个解决方案weak-strong dance,很漂亮的名字。其实现如下:

[objc] view plain copy

print?

  1. - (void)dealloc
  2. {
  3. [[NSNotificationCenter defaultCenter] removeObserver:_observer];
  4. }
  5. - (void)loadView
  6. {
  7. [superloadView];
  8. __weak TestViewController *wself = self;
  9. _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
  10. object:nil
  11. queue:nil
  12. usingBlock:^(NSNotification *note) {
  13. TestViewController *sself = wself;
  14. [sself dismissModalViewControllerAnimated:YES];
  15. }];
  16. }

在 block 使用 self 之前先用 __weak 修饰 self 创建一个 self 弱引用变量 ,然后在 block 中使用 self 之前先用 __strong 修饰创建一个 对该弱引用 self 的强引用,防止 self 被提前释放。

这样的话就可以打破循环引用了。

当然,__weak 和 __strong 只在 ARC 情形下有效;对于非 ARC ,就需要用到 __block 了,效果相同,如下:

[objc] view plain copy

print?

  1. - (void)dealloc
  2. {
  3. [[NSNotificationCenter defaultCenter] removeObserver:_observer];
  4. [_observer release];
  5. [superdealloc];
  6. }
  7. - (void)loadView
  8. {
  9. [superloadView];
  10. __block TestViewController *bself = self;
  11. _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
  12. object:nil
  13. queue:nil
  14. ngBlock:^(NSNotification *note) {
  15. [bself retain];
  16. [bself dismissModalViewControllerAnimated:YES];
  17. [bself release];
  18. }];
  19. }

三、ReactiveCocoa中的Weak-Strong Dance

例如:

[objc] view plain copy

print?

  1. @weakify(self);
  2. [RACObserve(self,photosArray) subscribeNext:^(id x){
  3. @strongify(self);
  4. [self.collectionView reloadData];
  5. }];

RACObserver is a C macro that takes two parameters: an object and a key path on that object. It returns a signal whose values are sent whenever the key path’s value changes. A completion value is sent when the object, in this case self, is deallocated. --> ? We subscribe to this signal in order to reload our collection view whenever our photosArray property is changed.

译注:RACObserver 是一个宏定义,有两个参数:an object and a key path on that object。当 object key path value 变化时,就会返回一个 signal。

我们对这个 signal 进行订阅,一旦 photoArray 属性发送变化,返回signal,就可以 reload collection view。

The weakify/strongify dance is all too common in Objective-C under ARC.Weakify creates a new, weak variable assigned to self. Strongify then creates a new, strong variable in its scope assigned to the weak self. When strongify does this, it’s using what’s called a “shadow variable” – so named because the new, strong variable is called self, replacing the former strong reference to self.

Basically, the subscribeNext: block is going to capture self in its lexical scope, causing a reference cycle between self and the block. The block is strongly referenced by the return value of subscribeNext:, a RACSubscriber instance. This is then captured by the RACObserver macro, which will be automatically deallocated once its first parameter, self is deallocated. Without the weakify/strongify invocations, self would never be deallocated.

译注:分析一下其中可能存在的 block 循环引用问题。

self --> RACObserver macro --> RACSubscriber instance --> block --> self. 假如不使用 weakify/strongify 那么现实其中的循环引用导致 self 始终无法释放。

最后友情提示:在使用时应该注意block的嵌套层数,不恰当的滥用多层嵌套block可能给程序的可维护性带来灾难。

时间: 2024-08-28 12:18:20

ReactiveCocoa Weak-Strong Dance的相关文章

Swift中的Weak Strong Dance

亲爱的博客园的关注着博主文章的朋友们告诉你们一个很不幸的消息哦, 这篇文章将会是博主在博客园发表的最后一篇文章咯, 因为之后的文章博主只会发布到这里哦 http://daiweilai.github.io/ 新博客排版布局更好,阅读体验更佳,欢迎吐槽.留言.订阅哟 马上又要过年了,诶,再也不能像当初那样无耻地逗利是了(我们广东的方言讨红包的意思) 图1 图2 看来今年没利了 谁让哥已经工作了呢. 公司今年的开发任务算是完结了,苹果又极不负(hǎo)责(yàng)任(de)地放圣诞不审核了,所以这

assign, retain, weak, strong, copy,unsafe_unretain

readonly, readwrite:是控制属性的访问权限,readonly只生成getter方法,其他类是无法修改其值的.readwrite是会同时生成getter和setter方法,其他类可以修改其值. assign, retain, weak, strong, copy,unsafe_unretained:在non-ARC中,assign和retain是一组,assign的对象属性引用计数不变,而retain会被+1.对应的在ARC中,weak和strong是一组,weak的对象属性引用

NSString NSMutableString copy mutableCopy retain weak strong

NSString 与 NSMutableString NSString是不可变字符串对象,这句话的意思,结合代码: #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { NSString *str = @"Shaw"; NSString *str1 = @"Root"; // NSString *str1的意思是str1

IOS编程学习(2):copy,nonatomic, retain,weak,strong用法

property属性? property:提供成员变量的访问方法的声明.控制成员变量的访问权限.控制多线程时成员变量的访问环境 .property不但可以在interface,在协议protocol.和类别category中也可以使用. synthesize 合成访问器方法? 实现property所声明的方法的定义.其实说直白就像是:property声明了一些成员变量的访问方法 ,synthesize则定义了由property声明的方法.他们之前的对应关系是  property 声明方法 ---

nonatomic, retain,weak,strong用法详解

strong weak strong与weak是由ARC新引入的对象变量属性 ARC引入了新的对象的新生命周期限定,即零弱引用.如果零弱引用指向的对象被deallocated的话,零弱引用的对象会被自动设置为nil. @property(strong) MyClass *myObject; 相当于@property(retain) MyClass *myObject; @property(weak) MyOtherClass *delegate; 相当于@property(assign) MyO

iOS开发 -------- Block技术中的weak - strong

一 Block是什么? 我们使用^运算符来声明一个Block变量,而且在声明完一个Block变量后要像声明普通变量一样,后面要加; 声明Block变量 int (^block)(int) = NULL; Block变量的语法 数据返回值类型 (^变量名)(参数列表) = NULL 赋值Block变量 block = ^(int m) { return m * m; }; 使用Block变量 // 通过使用block变量,计算整型常量10的平方,并且打印在控制器输出 NSLog(@"10的平方是:

【整理】Object-C中的属性(Property)的Setter:assign,copy,retain,weak,strong之间的区别和联系

iOS编程过程中,经常看到一些属性前面有些修饰符,比如copy,retain等. 这些关键字,是Object-C语言中,对于Property的setter. Mac官网: The Objective-C Programming Language – Declared Properties – Setter Semantics 中的解释是: Setter Semantics These attributes specify the semantics of a set accessor. They

copy weak strong assign等等

/** *  微博的内容(文字) */ @property (nonatomic, copy) NSString *text; /** *  微博的转发数 */ @property (nonatomic, assign) int reposts_count; /** *  微博的作者 */ @property (nonatomic, strong) IWUser *user; @property (nonatomic, strong) NSMutableArray *btns; @propert

循环引用 &amp;&amp; weak strong

@weakify _weak _weak @weakify(self); // RAC _weak的self_weak_变量 解决循环引用 问题: weakSelf是弱引用,会被释放 _weak typeof(self) weakSelf = self; self.block = ^{ dispatch_async(dispatch_get_global_queue(0,0),^{ [NSThread sleepForTimeInterval:1]; NSLog(@"%@",weakS

ios中关于property和arc的weak,strong

在ios中可以采用声明是属性来定义实例变量和属性 在.h文件中直接使用@property  在.m文件中使用扩张定义内部使用的的 格式位@property(参数1,参数2)类型  名称 参数有三类 1.读写属性的 :(readwrite/readonly/setter=/getter=) 2.setter语意:(assign/retain/copy) 3.原子性:(atomicity/nonatomic) 第一类 用于设置set和get方法sette=和getter=用于设置指定的get和set