2013-11-28 5 views
6

Я реализую свой первый код с https://github.com/ReactiveCocoa/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

Одиночный шаг через код и посмотреть, что происходит. Или установите контрольную точку при входе в sendNext и исследуйте стек вызовов каждый раз, когда он вызывается. –

ответ

9

Это происходит потому, что блок передается +[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]; 
    }]; 
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]; 

Этот новый, полученный сигнал будет посылать одни и те же сообщения об ошибках или для всех абонентов. Если сигнал завершается, и есть новый подписчик, он сразу же получит все сообщения.

Смежные вопросы