0

当我慢慢尝试围绕 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;
    }];
}];

这是做什么的:

我有一个视图控制器,它有一个名为projecttypeMyProject的属性和一个taskstype的属性NSArray。一个项目有一个tasks返回 s 数组的信号MyTask。可以随时从外部更改项目。我希望我的视图控制器在发生上述情况时做出响应并自行刷新。

我试图解决的问题:

我曾经[[project tasks] subscribeNext:...]在第一个块中,直到我意识到如果 webrequest 花费的时间太长并且我同时切换了项目,我会在新的上下文中从旧项目接收并分配数据!(此后不久,新数据集到达,一切恢复正常)。

尽管如此,这就是我遇到的问题,我通过使用该takeUntilBlock:方法解决了它。我的问题是:我怎样才能简化/重新设计这个?

4

1 回答 1

4

最自然地承担最近项目任务的关键操作员是-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];
于 2013-12-31T05:05:28.903 回答