我正在尝试为以下场景编写反应式解决方案。
点击按钮,如果数据库中有某些实体,则必须将用户推送到新的视图控制器,否则应尝试下载这些实体并再次执行检查。
这是我到目前为止所得到的:
// VIEW CONTROLLER
self.button.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
return self.viewModel.rac_checkEntitiesAvailability;
}];
[self.button.rac_command.executionSignals.flatten subscribeNext:^(id x) {
if([x boolValue] == YES) {
// Entities available, can perform segue
} else {
// Error
}];
// VIEW-MODEL
- (RACSignal*)rac_checkEntitiesAvailability {
return [[RACSignal return:@([Entity MR_countOfEntities] > 0)]
flattenMap:^RACStream *(id entitiesAvailable) {
if([entitiesAvailable boolValue]) {
return [RACSignal return:@YES];
} else {
return [[[self rac_downloadEntities] flattenMap:^RACStream *(id value) {
// This takes into account network problems too
return [RACSignal return:@([Entity MR_countOfEntities] > 0)];
}];
}
}];
}
它似乎有效,但作为我对ReactiveCocoa世界的新手,我不确定它是否真的正确或者可以用不那么冗余的方式编写。
非常感谢, DAN
答案 0 :(得分:1)
实际上,您不需要为按钮事件创建信号。 MVVM用于观察数据更改和自动更改UI。您可以编写如下代码:
button.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
if (xxx) {
// Entities available, can perform segue
} else {
// Error
}
return [RACSignal empty];
}];
或者您可以直接处理事件:
[[button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
if (xxx) {
// Entities available, can perform segue
} else {
// Error
}
}];
请勿尝试通过RAC解决所有问题。
===========
对于您的方案,您应该使用阻止。添加如下的下载功能:
@interface Entity ()
+ (int)MR_countOfEntities;
+ (void)MR_downloadEntites:(void(^)(void))finishBlock;
@end
@implementation Entity
static int _MR_countOfEntities = 0;
+ (int)MR_countOfEntities
{
return _MR_countOfEntities;
}
+ (void)MR_downloadEntites:(void (^)(void))finishBlock
{
// Download entites. This is an example.
[[AFHTTPRequestOperationManager manager] GET:@"http://test.com/entites" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
_MR_countOfEntities = 1;
finishBlock();
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
_MR_countOfEntities = 0;
finishBlock();
}];
}
@end
所以你可以像这样修改按钮的代码:
[[button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
if ([Entity MR_countOfEntities] > 1) {
// Entities available, can perform segue
} else {
[Entity MR_downloadEntites:^{
if ([Entity MR_countOfEntities] > 1) {
// Entities available, can perform segue
} else {
// Error
}
}];
}
}];
答案 1 :(得分:1)
我会诚实地建议在涉及UIControl时不要直接绑定控制事件。如果您使用RACCommand(在viewModel中声明和创建),您可以轻松地将UI绑定到下载状态(执行信号),在失败时显示警报消息,并在成功时显示新UI(如果需要)。 您修改后的代码版本对我来说似乎很好,但我可能会简化您的内部信号:您不需要在返回信号周围包含一个布尔“立即”变量(=您不需要信号就知道有多少您在CoreData模型中拥有的实体,它是一个同步操作)。 像这样的东西(检查语法,所有这些方括号可能是错的)
[RACSignal defer:^RACSignal *{
if([Entity MR_countOfEntities] > 0) {
return [RACSignal return:@YES];
} else {
return [[self rac_downloadEntities] flattenMap:^RACStream *(id value) {
// This takes into account network problems too
return [RACSignal return:@([Entity MR_countOfEntities] > 0)];
}];
}];