J'ai recherché un modèle approprié pour les commandes qui peuvent être annulées.
Voici le scénario:
L'utilisateur Joe souhaite se connecter au service Twitter sur son appareil. Il y a un bouton sur l'écran qui dit Twitter et lorsque l'utilisateur appuie dessus, le processus de connexion démarre et le texte sur le bouton change pour annuler. Le processus de connexion peut prendre une longue période de temps (30 secondes par exemple) et si l'utilisateur appuie à nouveau sur le bouton pendant ce temps, la connexion existante sera annulée.
J'ai essayé de nombreuses façons différentes de faire fonctionner ce produit, mais elles ont toutes une très mauvaise odeur. Voici la meilleure solution que j'ai trouvée jusqu'à présent:
<strong i="9">@property</strong> (strong, nonatomic) RACCommand *twitterLoginCommand;
<strong i="10">@property</strong> (strong, nonatomic) RACCommand *cancelCommand;
<strong i="11">@property</strong> (strong, nonatomic) id authenticatedUser;
<strong i="12">@property</strong> (weak, nonatomic) RACDisposable * authenticationDisposable;
-(void) viewDidLoad {
RAC(self, twitterButton.rac_command, self.twitterLoginCommand) = [[RACObserve(self, twitterLoginCommand.executing) flatten]
map:^id(NSNumber * value) {
@strongify(self);
if (value.boolValue) {
return self.cancelCommand;
} else {
return self.twitterLoginCommand;
}
}];
}
-(RACCommand *) cancelCommand {
if (!_cancelCommand) {
@weakify(self);
_cancelCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
@strongify(self);
[self.authenticationDisposable dispose];
return [RACSignal empty];
}];
}
return _cancelCommand;
}
- (RACCommand *)twitterLoginCommand {
if (!_twitterLoginCommand) {
@weakify(self);
_twitterLoginCommand = [[RACCommand alloc]initWithSignalBlock: ^RACSignal *(UIButton *button) {
@strongify(self);
RACSignal * signal = [self twitterSignInSignal];
self.authenticationDisposable = [signal subscribeNext:^(FAUser * user) {
self.authenticatedUser = user;
}error:^(NSError *error) {
self.authenticationDisposable = nil;
}];
return signal;
}];
}
return _twitterLoginCommand;
}
- (RACSignal *)twitterSignInSignal {
//Left out, returns a signal with a user
}
À l'origine, j'avais la commande Twitter souscrite dans viewDidLoad et utilisant un takeUntil pour le signal d'annulation (plutôt que d'utiliser le jetable et de s'abonner avec la commande), mais cela ne semblait pas empêcher la commande de s'exécuter immédiatement après l'annulation (la tâche de connexion resterait en cours d'exécution jusqu'à ce que le signal traite le takeUntil).
Essaye celui-là.
_twitterLoginCommand = [[RACCommand alloc] initWithSignalBlock:^(id _) {
@strongify(self);
return [[self
twitterSignInSignal]
takeUntil:self.cancelCommand.executionSignals];
}];
RAC(self.authenticatedUser) = [self.twitterLoginCommand.executionSignals switchToLatest];
Je vous suggère de déplacer les créations de commandes vers la méthode init
Cela a fonctionné comme un charme et tout sent bon. Merci, il m'a fallu quelques jours pour arriver aussi loin que j'étais, j'ai dû manquer quelque chose quand j'ai essayé une approche comme celle-là la dernière fois.
De rien!
RAC (self.authenticatedUser) = [self.twitterLoginCommand.executionSignals switchToLatest];
si changez-le en
RAC (self.authenticatedUser) = [self.twitterLoginCommand.executionSignals aplatir];
mieux ? @notxcain
Commentaire le plus utile
Essaye celui-là.
Je vous suggère de déplacer les créations de commandes vers la méthode init