关于 ios:Reactive Cocoa 和多个 AFNetworking 请求在短时间内

Reactive Cocoa and multiple AFNetworking requests in short period of time

我正在努力使用 AFNetworking 和 Reactive Cocoa 处理对 Web 服务的多个请求的方式。在这种情况下,用户要求 API 为字符/整数搜索输入提供一堆建议,以便从列表中选择一个城市。

这是我的代码:

当用户输入超过 3 个字符/整数时,首先执行的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (void)fetchData:(NSString *)searchText
{
    NSLog(@"%@", searchText);

    if ([searchText validateStringwithPattern:BKPostcodeRegEx]) {
        self.searchURL = [NSString stringWithFormat:@"%@location/postalCode/%@/%@", BKBaseURL, self.countryCode, searchText];
    } else if ([searchText validateStringwithPattern:BKCityRegEx]) {
        self.searchURL = [NSString stringWithFormat:@"%@location/city/%@/%@", BKBaseURL, self.countryCode, searchText];
    } else {
        NSLog(@"Error Alert - No Valid Input");
        return;
    }

    RAC(self, searchResults) = [[[self postRequest] map:^(NSDictionary *json) {
        NSArray *results = json[@"data"][@"locations"];
        return results;
    }] catch:^(NSError *error) {
        return [RACSignal return:@[]];
    }];
}

现在这是我实际创建信号并将其传递回 self.searchResults:

的地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (RACSignal *)postRequest
{
    return [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

        [self.requestOperationManager GET:self.searchURL parameters:self.params success:^(AFHTTPRequestOperation *operation, id responseObject) {
            [subscriber sendNext:responseObject];
            [subscriber sendCompleted];
        }failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            [subscriber sendError:error];
        }];

        return [RACDisposable disposableWithBlock:^{
            [self.requestOperationManager.operationQueue cancelAllOperations];
        }];

    }] doError:^(NSError *error) {
        NSLog(@"error: %@", [error description]);
    }] throttle:0.5];
}

我认为问题在于,我在当前信号之前的信号完成之前开始订阅信号,因此在我尝试再次订阅时导致异常。

* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Signal name: [[[[+createSignal:] -doError:] -throttle: 0.500000]
-map:] -catch: is already bound to key path"searchResults" on object , adding signal
name: [[[[+createSignal:] -doError:]
-throttle: 0.500000] -map:] -catch: is undefined behavior'

我的猜测是我必须在 postRequest 方法中尝试这样的事情,但这似乎不是开箱即用的:

1
2
3
4
5
if (self.requestOperationManager.operationQueue.operationCount == 1) {
  NSLog(@"cancel all operations");
  [self.requestOperationManager.operationQueue cancelAllOperations];
  [subscriber sendCompleted];
}


您只能在任何给定对象的键路径上调用一次 RAC()。看起来 -fetchData: 可以被多次调用,这将导致 RAC() 在同一个对象和键路径上被多次调用。

通常,您在某种设置方法(例如初始化程序或 -[UIViewController loadView])中调用 RAC(),以便它只被调用一次。与其等到用户输入超过 3 个字符然后调用 -fetchData:,不如考虑如何创建一个在用户输入超过 3 个字符时发送值的信号,并将该信号分配给 RAC()\\' d 财产。例如(完全未经测试):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- (void)someInitializationMethod
{
    RACSignal *moreThan3 = [[myTextField rac_textSignal] filter:^(NSString *text) {
        return [text length] > 2;
    }];

    RAC(self, searchResults) = [self rac_liftSelector:@selector(fetchData:) withSignals:moreThan3];
}

- (void)fetchData:(NSString *)searchText
{
    if ([searchText validateStringwithPattern:BKPostcodeRegEx]) {
        // ... etc ...
    }

    return [[[self postRequest] map:^(NSDictionary *json) {
        NSArray *results = json[@"data"][@"locations"];
        return results;
    }] catch:^(NSError *error) {
        return [RACSignal return:@[]];
    }];
}

- (RACSignal *)postRequest
{
    // ... etc ...