2013-08-04 3 views
5

Ho una notifica di successo e una notifica di errore che arriva attraverso NSNotificationCenter. Ho scritto alcuni test per capire come combinare i segnali provenienti da queste due notifiche in un segnale che fornisce un errore quando la notifica di errore ha esito positivo e un successivo seguito da un completo quando viene raggiunta la notifica di esito positivo.Qual è il modo preferito per creare un segnale di segnali da combinare con i segnali e completare quando completi o errori?

Attualmente non vengono colpiti i blocchi completi, quindi viene colpito l'errore.

Inoltre, domanda di bonus secondario: perché @ [errorNotification, completeNotification] .rac_sequence.signal fa la stessa cosa del segnale di creazione del segnale in basso?

Codice:

-(void)test_flatten_signal_of_signals_and_convert_notification_to_error{ 
    RACSignal *errorNotification = [[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"TEST_FAILURE" object:nil] take:1]; 


    errorNotification = [errorNotification flattenMap:^(NSNotification *notification){ 
     return [RACSignal error:[NSError errorWithDomain:@"RAC_TEST" code:1 userInfo:nil]]; 
    }]; 

    RACSubject *completeNotification = [RACSubject subject]; 

    RACSignal *signalOfSignals = [[RACSignal 
            createSignal:^RACDisposable *(id<RACSubscriber> subscriber){ 
             [subscriber sendNext:errorNotification]; 
             [subscriber sendNext:completeNotification]; 
             [subscriber sendCompleted]; 
             return nil; 
            }] 
            flatten]; 


    __block BOOL hitCompleted = NO; 

    [signalOfSignals 
    subscribeNext:^(id val){ 
     STFail(nil); 
    } 
    error:^(NSError *err){ 
     hitCompleted = YES; 
    } 
    completed:^{ 
     STFail(nil); 
    }]; 

    [[NSNotificationCenter defaultCenter] postNotificationName:@"TEST" object:self]; 

    STAssertTrue(hitCompleted, nil); 
} 

-(void)test_flatten_signal_of_signals_and_hits_next_complete_on_notification{ 
    RACSubject *errorNotification = [RACSubject subject]; 

    RACSignal *completeNotification = [[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"TEST_SUCESS" object:nil] take:1]; 

    RACSignal *signalOfSignals = [[RACSignal 
            createSignal:^RACDisposable *(id<RACSubscriber> subscriber){ 
             [subscriber sendNext:errorNotification]; 
             [subscriber sendNext:completeNotification]; 
             [subscriber sendCompleted]; 
             return nil; 
            }] 
            flatten]; 


    __block BOOL hitCompleted = NO; 
    __block BOOL hitNext = NO; 
    [signalOfSignals 
    subscribeNext:^(id val){ 
     hitNext = YES; 
    } 
    error:^(NSError *err){ 
     STFail(nil); 
    } 
    completed:^{ 
     hitCompleted = YES; 
    }]; 

    [[NSNotificationCenter defaultCenter] postNotificationName:@"TEST_SUCCESS" object:self]; 

    STAssertTrue(hitCompleted, nil); 
    STAssertTrue(hitNext, nil); 
} 
+0

Suppongo che quando nel tuo primo test invii il nome della notifica come solo "TEST" intendi "TEST_FAILURE", giusto? – yonosoytu

+0

Sì. Questo è stato un bug nel mio test. D'oh. – Jon

risposta

11

Si può fare questo con gli operatori built-in:

RACSignal *successNotification = [[NSNotificationCenter.defaultCenter 
    rac_addObserverForName:SuccessNotification object:nil] 
    take:1]; 

RACSignal *errorNotification = [[NSNotificationCenter.defaultCenter 
    rac_addObserverForName:FailureNotification object:nil] 
    flattenMap:^(NSNotification *notification) { 
     // Convert to a meaningful error somehow. 
     NSError *error = …; 

     return [RACSignal error:error]; 
    }]; 

RACSignal *signal = [RACSignal merge:@[ successNotification, errorNotification ]]; 

Questo si prende cura di disposizione per voi, e più indica chiaramente come ognuna delle notifiche sono mappati su un valore o un errore.

Il segnale creato invierà i suoi valori in modo asincrono, a differenza del segnale creato nell'esempio.

3

Qualcosa come questo funziona per me in entrambi i casi di successo e fallimento:

RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { 
    RACDisposable *success = [[[[NSNotificationCenter defaultCenter] 
          rac_addObserverForName:@"TEST_SUCESS" object:nil] 
          take:1] 
          subscribeNext:^(id x) { 
           [subscriber sendNext:x]; 
          } completed:^{ 
           [subscriber sendCompleted]; 
          }]; 
    RACDisposable *failure = [[[[NSNotificationCenter defaultCenter] 
          rac_addObserverForName:@"TEST_FAILURE" object:nil] 
          take:1] 
          subscribeNext:^(id x) { 
          [subscriber sendError: 
           [NSError errorWithDomain:@"RAC_TEST" code:1 userInfo:nil]]; 
          }]; 
    return [RACDisposable disposableWithBlock:^{ 
    [success dispose]; 
    [failure dispose]; 
    }]; 
}]; 

creo un unico segnale con entrambi monouso. I segnali di successo inviano "successivo" e "completato" (lo take:1 è importante per il completamento del lavoro). Il segnale di errore invia l'errore. L'idea sta utilizzando il subscriber inviato nel blocco per inoltrare correttamente gli eventi negli altri due segnali.

+0

Grazie per la risposta ... L'unico cambiamento è che ho appiattito il segnale di notifica degli errori in [RACSigna error:] invece di iscriverti dopo ho appena sottoscritto l'errore e lo inoltro. – Jon

+0

Guarda Justin rispondere a questa domanda. La sua risposta non ha bisogno di un sottoscrittore esplicito, che è sempre meglio. – yonosoytu

Problemi correlati