我正在使用https://github.com/ReactiveCocoa/ReactiveCocoa实现我的第一个代码。
用于登录用户。行[subscriber sendNext:user];
被调用两次,但我希望只有一行。并且根本没有调用地图(因此永远不会调用自动登录)
这是我的实施:
-(RACSignal *) login:(NSString *)email pwd:(NSString *)pwd
{
DDLogInfo(@"Login user %@", email);
RACSignal *login = [RACSignal createSignal:^ RACDisposable *(id<RACSubscriber> subscriber)
{
[PFUser logInWithUsernameInBackground:email password:pwd block:^(PFUser *user, NSError *error) {
if (error) {
[subscriber sendError:error];
} else {
[subscriber sendNext:user];
[subscriber sendCompleted];
}
}];
return nil;
}];
[login map:^(PFUser *user) {
return [self autoLogin:user];
}];
return login;
}
这样叫:
NSString *email = data[@"email"];
NSString *pwd = data[@"pwd"];
[SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeBlack];
RACSignal *login = [[SyncEngine server] login:email pwd:pwd];
[login
subscribeCompleted:^
{
[[NSNotificationCenter defaultCenter]
postNotificationName:NOTIFY_LOGIN_CHANGED
object:self];
[SVProgressHUD showSuccessWithStatus:LOC_OK];
[self cancelForm];
}];
[login
subscribeError:^(NSError *error)
{
[SVProgressHUD dismiss];
[AppUrls alertError:LOC_ERROR_LOGING msg:error.userInfo[@"error"]];
}];
答案 0 :(得分:10)
这是因为传递给+[RACSignal createSignal:]
的块只要对信号进行订阅就会执行,并且您的代码会创建两个单独的订阅:
[login subscribeCompleted:^{ ... }];
[login subscribeError:^(NSError *error) { ... }];
如果您只想创建单个订阅,请使用方法-[RACSignal subscribeError:completed:]
:
[login subscribeError:^(NSError *error) {
[SVProgressHUD dismiss];
[AppUrls alertError:LOC_ERROR_LOGING msg:error.userInfo[@"error"]];
}
completed:^{
[[NSNotificationCenter defaultCenter]
postNotificationName:NOTIFY_LOGIN_CHANGED
object:self];
[SVProgressHUD showSuccessWithStatus:LOC_OK];
[self cancelForm];
}];
答案 1 :(得分:5)
虽然有时this solution可能就是您所需要的,但有时您确实希望确保只调用一次订阅块,可能是因为它会产生副作用。在这种情况下,您可以返回呼叫-replay
的信号:
return [[RACSignal createSignal:^ RACDisposable *(id<RACSubscriber> subscriber) {
[PFUser logInWithUsernameInBackground:email password:pwd block:^(PFUser *user, NSError *error) {
if (error) {
[subscriber sendError:error];
} else {
[subscriber sendNext:user];
[subscriber sendCompleted];
}
}];
return nil;
}] map:^(PFUser *user) {
return [self autoLogin:user];
}] replay];
这个新的派生信号会向所有订阅者发送相同的消息或错误。如果信号完成,并且有新订户,则会立即收到所有消息。