2013-11-28 9 views
6

Ich implementiere meinen ersten Code mit https://github.com/ReactiveCocoa/ReactiveCocoa.Warum wird das Signal in ReactiveCacoa zweimal aufgerufen?

Ist für die Anmeldung ein Benutzer. Die Zeile [subscriber sendNext:user]; wird zweimal aufgerufen, aber ich erwarte, dass ich nur eins bin. Und die Karte gar nicht aufgerufen wird (so die automatische Anmeldung wird nie aufgerufen)

Dies ist meine Implementierung:

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

auf diese Weise aufgerufen:

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

Schritt für Schritt durch den Code und sehen, was passiert. Oder setzen Sie einen Haltepunkt bei der Eingabe von sendNext und prüfen Sie den Aufruf-Stack jedes Mal, wenn er aufgerufen wird. –

Antwort

9

Dies geschieht, weil der Block übergeben +[RACSignal createSignal:] ausführt, wenn ein Abonnement auf das Signal gemacht wird, und Ihr Code erstellt zwei separate Abonnements:

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

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

Wenn Sie nur ein einziges Abonnement erstellen möchten, verwenden Sie die Methode -[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

Während manchmal this solution alles, was Sie brauchen könnten, manchmal wollen Sie das Abonnement-Block um sicherzustellen, dass nur ein einziges Mal genannt wird, vielleicht, weil es erzeugt Nebenwirkungen. In diesem Fall können Sie das Signal Aufruf -replay zurück:

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]; 

Dieses neue, wird abgeleitete Signal an alle Teilnehmer, die die gleichen Nachrichten oder Fehler senden. Wenn das Signal abgeschlossen ist und ein neuer Teilnehmer vorhanden ist, empfängt dieser sofort alle Nachrichten.

Verwandte Themen