2013-11-28 22 views
6

Wdrażam mój pierwszy kod z https://github.com/ReactiveCocoa/ReactiveCocoa.Dlaczego sygnał jest wywoływany dwa razy w ReactiveCocoa?

Jest przeznaczony do zalogowania się jako użytkownik. Linia [subscriber sendNext:user]; jest wywoływana dwukrotnie, ale spodziewam się, że będzie tylko jedna. A mapa nie nazywa się w ogóle (tak autologowanie nigdy nazywa)

To jest moje wykonanie:

-(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; 
} 

Nazywa ten sposób:

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

Wykonaj pojedynczy krok kodu i zobacz, co się dzieje. Lub ustaw punkt przerwania na wejściu do sendNext i sprawdź stos wywołań za każdym razem, gdy zostanie wywołany. –

Odpowiedz

9

Dzieje się tak dlatego, że blok przekazane +[RACSignal createSignal:] jest wykonywany po wygenerowaniu subskrypcji sygnału, a kod tworzy dwie osobne subskrypcje:

[login subscribeCompleted:^{ ... }]; 

[login subscribeError:^(NSError *error) { ... }]; 

Jeśli chcesz tylko utworzyć jeden abonament, należy użyć metody -[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

Chociaż czasami this solution może być wszystko, czego potrzebujemy, to czasami chcą upewnić się, że blok subskrypcja jest wywoływana tylko raz, może dlatego, wywołuje efekty uboczne. W tym przypadku można powrócić sygnał wzywający -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]; 

Ten nowy sygnał pochodzący wyśle ​​te same wiadomości lub błąd do wszystkich abonentów. Jeśli sygnał się zakończy i pojawi się nowy subskrybent, natychmiast otrzyma również wszystkie wiadomości.

Powiązane problemy