当我慢慢地尝试围绕 ReactiveCocoa 进行思考时,我编写了这段代码,并且我相当确定有更好的方法来解决我的问题。我非常感谢有关如何改进/重新设计我的情况的意见。
@weakify(self);
[RACObserve(self, project) subscribeNext:^(MyProject *project) {
@strongify(self);
self.tasks = nil;
[[[project tasks] takeUntilBlock:^BOOL(NSArray *tasks) {
if ([tasks count] > 0) {
MyTask *task = (MyTask *)tasks[0];
BOOL valid = ![task.projectID isEqualToString:self.project.objectID];
return valid;
}
return NO;
}] subscribeNext:^(NSArray *tasks) {
self.tasks = tasks;
}];
}];
这是做什么的:
我有一个 View Controller,它有一个名为 project
的 MyProject
属性和一个 tasks
NSArray
属性>。一个项目有一个 tasks
信号,它返回一个 MyTask
数组。可以随时从外部更改项目。我希望我的 View Controller 在上述情况发生时做出响应并自行刷新。
我要解决的问题:
我曾经在第一个 block 中[[project tasks] subscribeNext:...]
,直到我意识到如果 webrequest 花费的时间太长并且我同时切换了项目,我收到并在新环境中分配旧项目的数据! (此后不久,新数据集到达,一切恢复正常)。
不过,这就是我遇到的问题,我通过使用 takeUntilBlock:
方法解决了它。我的问题是:我如何简化/重新设计它?
最佳答案
最自然地接管最近项目任务的关键运算符是 -switchToLatest
.此运算符获取信号中的一个信号并返回一个信号,该信号仅发送从最新信号发送的值。
如果这听起来太抽象,将它放在您的领域中会有所帮助。首先,您有一个项目信号,特别是 RACObserve(self, project)
。然后,您可以将此项目信号 -map:
转换为包含调用 -tasks
的结果的信号,这恰好会返回一个信号。现在你有一个信号的信号。将 -switchToLatest
应用于任务信号的信号将为您提供任务信号,但只会发送来自最近项目的任务,而不会发送来自先前分配项目的“旧”任务。
在代码中,这看起来像:
[[RACObserve(self, project)
map:^(MyProject *project) {
return [project tasks];
}]
switchToLatest];
另一个可以用来简化代码的习惯用法是使用 RAC()
宏,它分配给一个属性,同时避免显式订阅。
RAC(self, tasks) = [[RACObserve(self, project)
map:^(MyProject *project) {
return [project tasks];
}]
switchToLatest];
更新
为了解决评论中的问题,这里有一个示例,说明如何在项目更改后将 tasks
属性初始化为 nil
,以及一种简单的方法处理 -tasks
信号中的错误。
RAC(self, tasks) = [[RACObserve(self, project)
map:^(MyProject *project) {
return [[[project
tasks]
startsWith:nil]
catch:^(NSError *error) {
[self handleError:error];
return [RACSignal return:nil];
}];
}]
switchToLatest];
关于ios - 使用 ReactiveCocoa 在模型更新时查看 Controller 状态更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20850873/