我使用reactivecococoa更新aUILabel而aUIProgressView倒计时:

NSInteger percentRemaining = ...;
self.progressView.progress = percentRemaining / 100.0;

__block NSInteger count = [self.count];

[[[RACSignal interval:0.05 onScheduler:[RACScheduler mainThreadScheduler]]
    take: percentRemaining]
    subscribeNext:^(id x) {
        count++;
        self.countLabel.text = [NSString stringWithFormat:@"%d", count];
        self.progressView.progress = self.progressView.progress - 0.01;
    } completed:^{
        // Move along...
    }];

这工作得很好,但是,对于count变量或者通过读取self.progressView.progress的值来减小它,我都不太满意。
我觉得我应该能够直接使用RAC宏发出信号并绑定属性。类似:
RACSignal *baseSignal = [[RACSignal interval:0.05 onScheduler:[RACScheduler mainThreadScheduler]]
                            take: percentRemaining]

RAC(self, countLabel.text) = [baseSignal
                                  map: ...
                                  ...

RAC(self, progressView.progress) = [baseSignal
                                        map: ...
                                        ...

...显示了我被困的地方。我不太清楚如何构造RACSignal,这样就不需要依赖状态变量。
此外,我不确定流完成时,在哪里/如何注入我需要的// Move along...副作用。
一旦你想对了方法,我相信这两种方法都足够简单,但是,任何帮助都会非常感谢。

最佳答案

如有疑问,请退房
RACSignal+Operations.h

RACStream.h
因为你想做的事情肯定会有接线员。在这种情况下,
最基本的缺失是
-scanWithStart:reduce:
不过,首先让我们看看baseSignal。逻辑将保持不变
基本上是一样的,只是我们应该发表aconnection
对于它:

RACMulticastConnection *timer = [[[RACSignal
    interval:0.05 onScheduler:[RACScheduler mainThreadScheduler]]
    take:percentRemaining]
    publish];

这样我们就可以在所有的依赖之间共享一个计时器。
信号。虽然你提供的baseSignal也可以工作,那会
为每个订阅服务器创建一个计时器(包括依赖信号),这可能
导致他们射击的微小差异。
现在,我们可以使用-scanWithStart:reduce:来增加countLabel
并减小progressView。此运算符获取以前的结果
当前值,并允许我们转换或组合它们,无论我们想要什么。
不过,在我们的例子中,我们只想忽略当前值(发送的
通过NSDate),所以我们只需操作上一个:
RAC(self.countLabel, text) = [[[timer.signal
    scanWithStart:@0 reduce:^(NSNumber *previous, id _) {
        return @(previous.unsignedIntegerValue + 1);
    }]
    startWith:@0]
    map:^(NSNumber *count) {
        return count.stringValue;
    }];

RAC(self.progressView, progress) = [[[timer.signal
    scanWithStart:@(percentRemaining) reduce:^(NSNumber *previous, id _) {
        return @(previous.unsignedIntegerValue - 1);
    }]
    startWith:@(percentRemaining)]
    map:^(NSNumber *percent) {
        return @(percent.unsignedIntegerValue / 100.0);
    }];

上面的+interval:运算符似乎是多余的,但这是
必须确保-startWith:text
发送了任何东西。
然后,我们将使用普通订阅完成。完全是
可能这些副作用也会变成信号,但是
不看密码很难知道:
[timer.signal subscribeCompleted:^{
    // Move along...
}];

最后,因为我们使用了上面的progress,所以实际上没有
开火了。必须手动启动连接:
[timer connect];

这将连接所有上述订阅,并启动定时器,因此
值开始流向属性。
现在,这明显比命令等价的代码多,所以可能
问问为什么值得。有几个好处:
值计算现在是线程安全的,因为它们不依赖于side
影响。如果你需要实现更昂贵的东西,那是非常容易的
将重要工作移到后台线程。
同样,这些值的计算是相互独立的。他们
如果这变得有价值,可以很容易地并行化。
所有的逻辑现在都是绑定的本地逻辑。你不必怀疑
更改来自或担心排序的位置(例如
初始化和更新),因为它都在一个地方,可以读取
自上而下。
这些值可以在不参考任何视图的情况下计算。为了
例如,在Model-View-ViewModel中,
计数和进程实际上是在aviewmodel中确定的,
然后视图层只是一组愚蠢的绑定。
变化的值仅来自一个输入。如果你突然需要
合并另一个输入源(例如,真正的进程而不是计时器),
你只需要换一个地方。
基本上,这是命令与函数编程的经典例子。
虽然命令式代码可以开始不那么复杂,但它的复杂性越来越高。
指数级。功能码(尤其是功能反应码)可以
开始更复杂,但是它的复杂性呈线性增长——这很重要。
随着应用程序的增长,管理起来更加容易。

关于objective-c - 拆分RACSignal以消除状态,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18852844/

10-10 11:49