ReactiveCocoa Weak-Strong Dance

本文探讨了Objective-C中Block引起的循环引用问题,并提出了使用@weakify和@strongify的方法来解决。此外,还介绍了在ReactiveCocoa中如何应用这一技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

一、block的循环引用问题

?
- (void)loadView
{
  [superloadView];
           
  _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
                                                                object:nil
                                                                 queue:nil
                                                            usingBlock:^(NSNotification *note) {
      [self dismissModalViewControllerAnimated:YES];  
  }];
}
- (void)dealloc
{
  [[NSNotificationCenter defaultCenter] removeObserver:_observer];
}

代码分析:

在上面代码中,我们添加向通知中心注册了一个观察者,然后在 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,很漂亮的名字。其实现如下:


- (void)dealloc
{
  [[NSNotificationCenter defaultCenter] removeObserver:_observer];
}
 
- (void)loadView
{
  [superloadView];
           
  __weak TestViewController *wself = self;
  _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
                                                                object:nil
                                                                 queue:nil
                                                            usingBlock:^(NSNotification *note) {
      TestViewController *sself = wself;
      [sself dismissModalViewControllerAnimated:YES];
  }];
}

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

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

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


- (void)dealloc
{
  [[NSNotificationCenter defaultCenter] removeObserver:_observer];
  [_observer release];
 
  [superdealloc];
}
 
- (void)loadView
{
  [superloadView];
           
  __block TestViewController *bself = self;
  _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
                                                                object:nil
                                                                 queue:nil
                                                               ngBlock:^(NSNotification *note) {
      [bself retain];
      [bself dismissModalViewControllerAnimated:YES];
      [bself release];
  }];
}

三、ReactiveCocoa中的Weak-Strong Dance

例如:


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

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可能给程序的可维护性带来灾难。

标题“51单片机通过MPU6050-DMP获取姿态角例程”解析 “51单片机通过MPU6050-DMP获取姿态角例程”是一个基于51系列单片机(一种常见的8位微控制器)的程序示例,用于读取MPU6050传感器的数据,并通过其内置的数字运动处理器(DMP)计算设备的姿态角(如倾斜角度、旋转角度等)。MPU6050是一款集成三轴加速度计和三轴陀螺仪的六自由度传感器,广泛应用于运动控制和姿态检测领域。该例程利用MPU6050的DMP功能,由DMP处理复杂的运动学算法,例如姿态融合,将加速度计和陀螺仪的数据进行整合,从而提供稳定且实时的姿态估计,减轻主控MCU的计算负担。最终,姿态角数据通过LCD1602显示屏以字符形式可视化展示,为用户提供直观的反馈。 从标签“51单片机 6050”可知,该项目主要涉及51单片机和MPU6050传感器这两个关键硬件组件。51单片机基于8051内核,因编程简单、成本低而被广泛应用;MPU6050作为惯性测量单元(IMU),可测量设备的线性和角速度。文件名“51-DMP-NET”可能表示这是一个与51单片机及DMP相关的网络资源或代码库,其中可能包含C语言等适合51单片机的编程语言的源代码、配置文件、用户手册、示例程序,以及可能的调试工具或IDE项目文件。 实现该项目需以下步骤:首先是硬件连接,将51单片机与MPU6050通过I2C接口正确连接,同时将LCD1602连接到51单片机的串行数据线和控制线上;接着是初始化设置,配置51单片机的I/O端口,初始化I2C通信协议,设置MPU6050的工作模式和数据输出速率;然后是DMP配置,启用MPU6050的DMP功能,加载预编译的DMP固件,并设置DMP输出数据的中断;之后是数据读取,通过中断服务程序从DMP接收姿态角数据,数据通常以四元数或欧拉角形式呈现;再接着是数据显示,将姿态角数据转换为可读的度数格
### Weak-to-Strong 3D Object Detection Using X-Ray Distillation X-ray distillation 是一种用于提升模型性能的技术,在计算机视觉领域中被广泛应用于从弱监督学习到强监督学习的任务转换。对于三维物体检测而言,这种方法可以通过利用标注较少的数据集来训练初始模型,并逐步增强其能力以适应更复杂的场景。 #### 方法概述 在 weak-to-strong 的框架下,X-ray distillation 主要通过以下几个方面实现: 1. **数据预处理与特征提取** 初始阶段通常依赖于大量未标注或部分标注的二维图像作为输入源[^1]。这些图像经过初步处理后,会生成对应的伪标签(pseudo-labels),从而构建起一个基础的三维空间表示。此过程可以借助现有的成熟算法完成,例如基于单目相机估计深度图或者使用多视角几何重建技术[^2]。 2. **教师-学生架构设计** 整体流程采用 teacher-student learning paradigm 来促进知识迁移。具体来说,“teacher model”是在高质量但数量有限的真实世界三维标注上训练而成;而“student model”,则主要依靠上述提到的大规模低质量甚至无标记样本进行优化调整[^3]。两者之间的交互方式即为所谓的 “distillation”。 ```python import torch.nn as nn class TeacherModel(nn.Module): def __init__(self, input_dim=3, output_dim=80): super(TeacherModel, self).__init__() self.layers = nn.Sequential( nn.Conv3d(input_dim, 64, kernel_size=(7, 7, 7), stride=(2, 2, 2)), ... ) def forward(self, x): return self.layers(x) class StudentModel(nn.Module): def __init__(self, input_dim=3, output_dim=80): super(StudentModel, self).__init__() self.layers = nn.Sequential( nn.Conv3d(input_dim, 32, kernel_size=(5, 5, 5), stride=(1, 1, 1)), ... ) def forward(self, x): return self.layers(x) ``` 3. **损失函数定义** 针对学生网络的学习目标,除了传统的分类交叉熵外还需要引入额外项用来衡量预测分布与老师输出的一致程度。常见的做法有 KL-divergence 或者 mean squared error (MSE)[^4]: \[ L_{total} = L_{cls}(y,\hat{y}) + \lambda * D(\text{{Teacher Output}},\text{{Student Output}}) \] 其中 \(L_{cls}\) 表示类别预测误差,\(D\) 可选自不同距离度量方法之一,参数 \(\lambda\) 控制二者权重平衡关系。 4. **迭代改进机制** 随着 student 模型逐渐接近 teacher 性能水平,则可进一步将其视为新的 teacher 并重复整个循环直至收敛为止[^5]。这种不断自我强化的过程有助于最终获得具备较强泛化能力和鲁棒性的解决方案。 --- #### 实验验证与应用前景 实验表明,该策略能够有效缓解传统端到端训练过程中因缺乏充分优质资源而导致的效果瓶颈问题[^6]。特别是在自动驾驶、医疗影像分析等领域内,当面临昂贵的人工标注成本时显得尤为重要。 尽管如此,仍需注意某些潜在挑战比如如何合理设置超参组合以及防止过拟合现象发生等问题都需要深入探讨研究。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值