当前位置: 首页 > news >正文

剖析RAC中的@weakify、@strongify

需要:pod 'YYKit'

 

在block语句块中,如果需引用self,而self对象中又持有block对象,就会造成循环引用循环引用(retain cycle),导致内存泄露,比如以下代码

self.block = ^{

        [self description];
    };

一般我们是这么解决的,使用一个__weal修饰的weakSelf变量指向self对象,在block中使用weakSelf:

 __weak typeof(self) weakSelf = self;
    self.block = ^{
[weakSelf description]; };

但是酱紫写,还是可能出问题,因为weakSelf是弱引用,而self一旦释放了,weakSelf可能为nil,还是举个栗子吧:
先定义一个TestObj对象,他的属性有一个block对象

@interface TestObj : NSObject@property (nonatomic, copy)void(^block)();@end@implementation TestObj- (void)dealloc {
    NSLog(@"%s",__func__);}- (instancetype)init {
    self = [super init];
    if (self) {

        __weak typeof(self) weakSelf = self;
        self.block = ^{
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
                [NSThread sleepForTimeInterval:1];
                NSLog(@"%@",weakSelf);
            });
        };
    }
    return self;
}

@end

执行testFunc方法,结果是打印的是(null),因为block里打印的方法是异步执行的,在 NSLog(@"%@",weakSelf);这句代码执行之前testFunc函数就结束,所以obj对象已经被release了。
怎么解决呢?所以再对weakSelf做一次 __strong就可以了:

__weak typeof(self) weakSelf = self;
        self.block = ^{

            __strong typeof(weakSelf) strongSelf = weakSelf;
            dispatch_async(dispatch_get_global_queue(0, 0), ^{

                [NSThread sleepForTimeInterval:1];
                NSLog(@"%@",strongSelf);
            });
        };
}

使用了__strongstrongSelf变量作用域结束之前,对weakSelf有一个引用,防止对象(self)提前被释放。而作用域一过,strongSelf不存在了,对象(self)也会被释放。

前面的写法虽然严谨了,也解决了问题了,但是作为喜欢偷懒的程序猿,会不会觉得很啰嗦?每次都要写那两条长长的__weak__strong,而且在block里用到的self的全部要改成strongSelf,假设把一段很多self的代码拷贝到block里,一个个改成strongSelf是不是很蛋疼?

只要在block外用了@weakify(self);然后再block里写@strongify(self);就可以了,@strongify(self);语句后的的self可以原封不动,好像很神奇,下面一起看看@weakify、@strongify 这两个神奇的宏最终替换了什么东西。
导入RAC的头文件,把上面的测试代码替换成RAC中用的@weakify(self);和@strongify(self), 分屏显示Xcode,让右侧的显示内容改为 preprocess“,就可以看到宏最终替换的结果。 

 

再比如:

     @weakify(self);
        _topView.block = ^(NSInteger tag) {
            
            @strongify(self);
            
            CGPoint point = CGPointMake(tag * SCREEN_WIDTH, self.scrollView.contentOffset.y);
            [self.scrollView setContentOffset:point animated:YES];
        };

 

转载于:https://www.cnblogs.com/xuzb/p/8872006.html

相关文章:

  • 解析PE资源表与重定位表
  • BTA | 周政军:区块链中侧链和分片解决不了的扩容问题,交给DAG吧!
  • PHP定时任务Crontab结合CLI模式详解
  • go append函数以及写入
  • mysql错误Table ‘./mysql/proc’ is marked as crashed and should be repaired
  • 于小镭:区块链将从三方面带来颠覆性认知革命
  • xtrabackup备份和还原
  • 什么时候使用HashMap?它有什么特点?
  • html中表格td的宽度如何设置
  • 关于form表单提交ajaxForm和ajaxSubmit的用法与区别
  • content属性为中文时导致html页面乱码问题
  • redis简单操作命令
  • To be or not
  • 工信部:全力做强软件和信息技术服务业
  • JavaScript工作原理(五):深入了解WebSockets,HTTP/2和SSE,以及如何选择
  • Dubbo 整合 Pinpoint 做分布式服务请求跟踪
  • ECS应用管理最佳实践
  • java概述
  • Mac转Windows的拯救指南
  • MQ框架的比较
  • PHP 的 SAPI 是个什么东西
  • php的插入排序,通过双层for循环
  • react 代码优化(一) ——事件处理
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • Zepto.js源码学习之二
  • 离散点最小(凸)包围边界查找
  • 你不可错过的前端面试题(一)
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 容器化应用: 在阿里云搭建多节点 Openshift 集群
  • 用jQuery怎么做到前后端分离
  • 用Visual Studio开发以太坊智能合约
  • 栈实现走出迷宫(C++)
  • nb
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • #define
  • #我与Java虚拟机的故事#连载05:Java虚拟机的修炼之道
  • #我与Java虚拟机的故事#连载18:JAVA成长之路
  • (C#)获取字符编码的类
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (黑马C++)L06 重载与继承
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (小白学Java)Java简介和基本配置
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • ***微信公众号支付+微信H5支付+微信扫码支付+小程序支付+APP微信支付解决方案总结...
  • ..回顾17,展望18
  • .bat批处理出现中文乱码的情况
  • .Net Core和.Net Standard直观理解
  • .NET Framework 4.6.2改进了WPF和安全性
  • .NET Micro Framework初体验(二)
  • .NetCore项目nginx发布
  • .net对接阿里云CSB服务
  • .w文件怎么转成html文件,使用pandoc进行Word与Markdown文件转化
  • @requestBody写与不写的情况
  • @value 静态变量_Python彻底搞懂:变量、对象、赋值、引用、拷贝