2014-03-13 6 views
5

Ich habe Folgendes ohne Erfolg versucht. Das Äquivalent mit -subscribeNext: funktioniert wie erwartet.Wie kann ich die Ausführung der Ausführungssignale eines Befehls ohne verschachteltes Abonnement abonnieren?

// A 
[[_viewModel.loginCommand.executionSignals flatten] subscribeCompleted:^{ 
    NSLog(@"A"); 
}]; 

Meine einzigen funktionierende Implementierung ist wie folgt:

// B 
[_viewModel.loginCommand.executionSignals subscribeNext:^(RACSignal *loginSignal) { 
    [loginSignal subscribeCompleted:^{ 
     NSLog(@"B"); 
    }]; 
}]; 

Warum in „A“ nicht -flatten Arbeit, und wie kann ich mich „B“ umschreiben nicht ein verschachteltes Abonnement zu benutzen?

Antwort

10

Der Operator -flatten gibt ein Signal zurück, das nur dann beendet wird, wenn alle inneren Signale vollständig sind, wodurch auch das äußere Signal abgeschlossen werden muss. Das gleiche gilt für -concat. Aus diesem Grund zeigt das resultierende Signal keine Darstellung der einzelnen Vervollständigung, sondern nur die abschließende Aggregatvervollständigung.

Alternativ zu verschachtelten Subskriptionen können Sie die inneren Signale so transformieren, dass sie einen Wert senden, der die Vervollständigung anzeigt. Eine Möglichkeit, dies zu tun, ist mit -materialize:

[[[_viewModel.loginCommand.executionSignals 
    map:^(RACSignal *loginSignal) { 
     // Using -ignoreValues ensures only the completion event is sent. 
     return [[loginSignal ignoreValues] materialize]; 
    }] 
    concat] 
    subscribeNext:^(RACEvent *event) { 
     NSLog(@"Completed: %@", event); 
    }]; 

Bitte beachte, dass ich verwenden -concat statt -flatten, da es die Semantik von RACCommand paßt ‚s serielle Standardausführung. Sie machen das gleiche in diesem Fall, -flatten degeneriert zu dem Verhalten von -concat, da der Befehl Signale nur nacheinander ausführt.

-materialize Verwendung ist nicht der einzige Weg, dies zu tun, es passiert einfach einen Wert zu senden, die Vollendung darstellt, sondern dass jeder Wert sein könnte, die Sie für Ihren Anwendungsfall entsprechend signifikant finden.

+2

Dies ist ziemlich üblich Operation - zeigen Sie die Bestätigung des Erfolgs der Operation. Ich möchte zum Beispiel eine Nachricht veröffentlichen und erwarte, dass der Vorgang fehlschlägt oder abgeschlossen wird. Gibt es wirklich keine Möglichkeit, es klarer zu machen? Ich meine, dieser Ansatz ist immer noch nur eine Subskription für das verschachtelte executionSignal. Was ist, wenn der Befehl beispielsweise mehr als ein Ausführungssignal hat? – Slabko

+2

'' executionSignals' von RACCommand' zeigt keine Vervollständigungsereignisse direkt an.Wenn Sie 'materialize' nicht verwenden möchten, besteht eine andere Möglichkeit darin, einen aussagekräftigen Wert zu verwenden, der" erfolgreich abgeschlossen "bedeutet. Im Falle eines Signals, das keine Werte sendet, können Sie einen beliebigen Wert senden, um die Vervollständigung anzuzeigen und sie einfach zu ignorieren. Ja, eine weitere Option ist die Verwendung des 'doCompleted:' - Operators als Alternative zum verschachtelten Abonnement. –

+2

Also RACCommand ist im Grunde nicht für die Verfolgung, wenn die Operation fehlgeschlagen oder erfolgreich ist, es ist nur über Tracking, wenn die Operation ausgeführt wird und wenn es nicht ist. Bekomme ich es richtig? – Slabko

0

Ich dachte gerade, technisch, erfolgreicher Abschluss ist nur eine Änderung des Ausführungszustandes auf NEIN, nachdem -executionSingals einen Wert mindestens einmal gesendet hat und kein Fehler, nachdem der Ausführungszustand das letzte Mal auf JA geändert wurde.

Basierend auf solchen Gedanken machte ich eine Kategorie:

#import "RACCommand+ARLCompletedSignal.h" 

@implementation RACCommand (ARLCompletedSignal) 

- (RACSignal *)completed 
{ 
    RACSignal *executing = self.executing; 
    RACSignal *signals = self.executionSignals; 
    RACSignal *errors = self.errors; 

    RACSignal *startingExecution = [RACSignal combineLatest:@[executing, [signals take:1]] 
                reduce:^id(NSNumber *executing, id _){ return executing; }]; 

    return [[startingExecution 
     ignore:@NO] 
     flattenMap:^RACStream *(id value) { 
      RACSignal *comletedOrFailed = [[executing ignore:@YES] subscribeOn:[RACScheduler scheduler]]; 
      return [[[comletedOrFailed take:1] takeUntil:errors] map:^id(id value) { return nil; }]; 
     }]; 
} 

@end 

Rubrik:

@interface RACCommand (ARLCompletedSignal) 

@property (nonatomic, readonly) RACSignal *completed; 

@end 

Hier -comleted Null sendet, wenn der Befehl seinen Betrieb erfolgreich abgeschlossen wurde. Auch bei https://gist.github.com/slabko/546de430a16994a5da8e können Sie die Version finden, die JA sendet, wenn der Vorgang erfolgreich abgeschlossen wird, oder NEIN, wenn nicht.

Ich versuchte es in einigen meiner ziemlich einfachen Fälle und es funktionierte. Bitte, lassen Sie es mich wissen, wenn es bei Ihnen nicht funktioniert.

Aber, glaube ich, in den meisten Fällen, abonnieren Sie die Fertigstellung des ursprünglichen Signals, bevor Sie es an den Befehl übergeben, ist die beste, "hackless" -Option.

Verwandte Themen