ios - ReactiveCocoa subscribeCompleted in command never executes -
i new reactivecocoa , mvvm. trying simple login screen. view controller in storyboard has 2 textfields (username, password) , 1 button. when button clicked should send post request username , password server , receive secure token. when response received, should execute sendcompleted. subscribecompleted in raccommand executionsignals block never gets executed , can't go next screen.
viewcontroller.m
// viewcontroller.m #import "viewcontroller.h" #import <reactivecocoa/reactivecocoa.h> #import <reactivecocoa/racextscope.h> #import "viewmodel.h" @interface viewcontroller () @property (strong, nonatomic) viewmodel *viewmodel; @property (weak, nonatomic) iboutlet uibutton *button; @property (weak, nonatomic) iboutlet uitextfield *usernametextfield; @property (weak, nonatomic) iboutlet uitextfield *passwordtextfield; @end @implementation viewcontroller - (instancetype)initwithcoder:(nscoder *)adecoder { self = [super initwithcoder:adecoder]; if (!self) return nil; _viewmodel = [viewmodel new]; return self; } - (void)viewdidload { [super viewdidload]; // reactive stuff rac(self.viewmodel, username) = self.usernametextfield.rac_textsignal; rac(self.viewmodel, password) = self.passwordtextfield.rac_textsignal; self.button.rac_command = self.viewmodel.logincommand; @weakify(self); // logged in [[[[self.viewmodel.logincommand.executionsignals logall] flattenmap:^racstream *(racsignal *execution) { // don't understand part well. flattenmap in particular example? return [execution ignorevalues]; // assume should ignore sendnext: }] subscribecompleted:^{ nslog(@"completed"); // subscribecompleted block never called! //[self performseguewithidentifier:@"nextscreen" sender:nil]; go next screen or similar }]; // error occured during login [self.viewmodel.logincommand.errors subscribenext:^(id error) { // works fine. nslog(@"login error: %@", error); // show alert view }]; } @end
viewmodel.h
// viewmodel.h #import <foundation/foundation.h> @class raccommand; @interface viewmodel : nsobject @property (nonatomic, readonly) raccommand *logincommand; @property (strong, nonatomic) nsstring *username; @property (strong, nonatomic) nsstring *password; @property (nonatomic, readonly, getter=isloading) bool loading; // used loading indicatior view. @end
viewmodel.m
// viewmodel.m #import "viewmodel.h" #import <reactivecocoa/reactivecocoa.h> #import <reactivecocoa/racextscope.h> @interface viewmodel () @property (strong, nonatomic) raccommand *logincommand; @property (nonatomic, assign, getter=isloading) bool loading; @end @implementation viewmodel // initializer - (instancetype)init { self = [super init]; if (!self) return nil; _networkmanager = [networkmanager shared]; return self; } // getter - (raccommand*)logincommand { if (_logincommand) { _logincommand = [[raccommand alloc]initwithenabled:[self validatelogininputs] signalblock:^racsignal *(id input) { return [self loginusersignal]; }]; } return _logincommand; } // methods - (racsignal*)validatelogininputs { return [racsignal combinelatest:@[racobserve(self, username), racobserve(self, password)] reduce:^id(nsstring *username, nsstring *password) { return @(username.length > 0 && password.length > 0); }]; } - (racsignal*)loginusersignal { @weakify(self); return [[[[racsignal createsignal:^racdisposable *(id<racsubscriber> subscriber) { @strongify(self); self.loading = yes; [self.networkmanager validateloginwithusername:self.username password:self.password success:^(nsdictionary *jsonresponse) { [subscriber sendnext:jsonresponse]; [subscriber sendcompleted]; // doesnt work } failure:^(nserror *error) { [subscriber senderror:error]; // works }]; }] donext:^(id x) {; // save secure token memory }] finally:^{ // when error occurs or complete, stop animation spinner. @strongify(self); self.loading = no; }] replaylazily]; }
update
i did this:
[self.viewmodel.logincommand.executionsignals subscribenext:^(id signal) { [signal subscribenext:^(id x) { nslog(@"logged in successfully"); // [self perfromseguewithidentifier:@"setpin" sender:nil]; }]; }];
but don't think clean solution.
self.viewmodel.logincommand.executionsignals - not send "completed"
viewmodel.h
@property (nonatomic, strong, readonly) racsignal *completed;
viewmodel.m
self = [super init]; if (self) { racsubject *completed = [racsubject subject]; _completed = completed; [[[self.logincommand.executionsignals map:^id(racsignal *value) { return [value docompleted:^{ [completed sendcompleted]; }]; }] switchtolatest] subscribenext:^(id x) { }]; return self; }
Comments
Post a Comment