objective-creactive-cocoa

ReactiveCocoa observe two properties


When observing just one property the following code works fine:

[[[[RACObserve(self, userName) ignore:nil]
           flattenMap:^(NSString *userName) {

               return [self authenticateUserWithUserName:userName andPassword:@"password"];

           }] deliverOn:RACScheduler.mainThreadScheduler]
         subscribeError:^(NSError *error) {

             // TODO: Propagate error

         }];

But when a try to observe two properties at the same time I don't get the results back:

 [[[RACSignal
            combineLatest:@[ [RACObserve(self, userName) ignore:nil],
                             [RACObserve(self, password) ignore:nil] ]
            reduce:^(NSString *userName,
                     NSString *password) {

                return [self authenticateUserWithUserName:userName andPassword:password];

            }]deliverOn:RACScheduler.mainThreadScheduler]
          subscribeError:^(NSError *error) {

              // TODO: Propagate error

          }];

Here is the rest of the code:

 @property (nonatomic, strong) PFPClient *client;

 -(RACSignal *)authenticateUserWithUserName:(NSString *)userName andPassword:(NSString *)password {

     return [[self.client authenticateUser:_userName withPassword:_password] doNext:^(PFPAccessToken *accessToken) {
         self.accessToken = accessToken;
     }];
      }

The client class:

 -(RACSignal *)authenticateUser:(NSString *)userName withPassword:(NSString *)password {

     NSString *urlString = [NSString stringWithFormat:@"https://xxxx?username=%@&password=%@", userName, password];
     NSURL *url = [NSURL URLWithString:urlString];

     return [[self fetchJSONFromURL:url] map:^(NSDictionary *json) {
         return [MTLJSONAdapter modelOfClass:[PFPAccessToken class] fromJSONDictionary:json error:nil];
     }];
      }

 -(RACSignal *)fetchJSONFromURL:(NSURL *)url {

     NSLog(@"Fetching: %@", url.absoluteString);

     // When observing two properties, next block is never executed...

     return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

         NSLog(@"Opening request...");
         NSURLSessionDataTask *dataTask = [self.session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse
 *response, NSError *error) {

             NSLog(@"Request finished.");
             if (! error) {
                 NSError *jsonError = nil;
                 id json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonError];
                 if (! jsonError) {
                     [subscriber sendNext:json];
                 }
                 else {
                     [subscriber sendError:jsonError];
                 }
             }
             else {
                 [subscriber sendError:error];
             }

             [subscriber sendCompleted];

         }];

         [dataTask resume];

         return [RACDisposable disposableWithBlock:^{
             [dataTask cancel];
         }];

     }] doError:^(NSError *error) {

         NSLog(@"%@",error);

     }]; }

Any idea of what I'm doing wrong?


EDIT. The call has to be done like this:

[[[[RACSignal
            combineLatest:@[ [RACObserve(self, userName) ignore:nil],
                             [RACObserve(self, password) ignore:nil] ]]
           flattenMap:^(RACTuple *userNameAndPassword) {

               RACTupleUnpack(NSString *userName, NSString *password) = userNameAndPassword;
               return [self authenticateUserWithUserName:userName andPassword:password];

           }]
          deliverOn:RACScheduler.mainThreadScheduler]
         subscribeError:^(NSError *error) {

             // TODO: Propagate error

         }];

Solution

  • [[[RACSignal
               combineLatest:@[ [RACObserve(self, userName) ignore:nil],
                                [RACObserve(self, password) ignore:nil] ]]
               flattenMap:^(RACTuple *userNameAndPassword) {
                   RACTupleUnpack(NSString *userName, NSString *password) = userNameAndPassword;
                   return [self authenticateUserWithUserName:userName andPassword:password];
               }]
               deliverOn:RACScheduler.mainThreadScheduler]
               subscribeError:^(NSError *error) {
    
                   // TODO: Propagate error
    
               }];