【问题标题】:ReactiveCocoa observe two propertiesReactiveCocoa 观察两个属性
【发布时间】:2014-07-21 22:00:43
【问题描述】:

仅观察一个属性时,以下代码可以正常工作:

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

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

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

             // TODO: Propagate error

         }];

但是当我尝试同时观察两个属性时,我没有得到结果:

 [[[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

          }];

下面是剩下的代码:

 @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;
     }];
      }

客户端类:

 -(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);

     }]; }

知道我做错了什么吗?


编辑。调用必须像这样:

[[[[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

         }];

【问题讨论】:

  • 诀窍在于flattenMap。您可以将map 调用转换为combineLatest:reduce: 调用,但flattenMap 的作用更多——即在映射后变平。
  • 谢谢,这就是解决方案。

标签: objective-c reactive-cocoa


【解决方案1】:
[[[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

           }];

【讨论】:

  • 我会添加一些小评论。你忘了插入@weakify(self) 和@strongify(self)
【解决方案2】:

使用 Swift 非常简单

let emailSignal = self.textFieldEmail.reactive.continuousTextValues
let passwordSignal = self.textFieldPassword.reactive.continuousTextValues
emailSignal.combineLatest(with: passwordSignal).observeValues { (mail, password) in
    guard let mailText = mail, let passwordText = password else {
        self.buttonLogin.isEnabled = false
        return
    }
    self.buttonLogin.isEnabled = mailText.count > 0 && passwordText.count > 0
}

【讨论】:

    猜你喜欢
    • 2017-10-19
    • 2016-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多