I have just started learning reactivecocoa. i want to perform network operation for each entry in a collection object and parse return result, mark the entry as invalid if an error is reported.

The following example illustrate the problem. urlList array is having 4 entries.2 entries generates error (generates connection closed and timeout error). so subscribe block is not notified for all the entries.

- (RACSignal *)processStationList
{
    NSArray *urlList = @[@"http://66.55.93.205/listen.pls",@"http://84.20.77.50:8000/listen.pls",@"http://valekalter.serverroom.us:9264/listen.pls", @"http://66.55.93.205:8080/listen.pls"];

    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [[urlList.rac_sequence.signal flattenMap:^RACStream *(NSString *urlString) {
            NSLog(@"flatten map %@",urlString);
            return [self fetchStationURLListForStation:urlString];
        }] subscribeNext:^(id x) {
            NSLog(@"suscribe next %@",x);
            [subscriber sendNext:x];
        } error:^(NSError *error) {
            NSLog(@"suscribe error %@",error);
            [subscriber sendNext:nil];
        } completed:^{
            NSLog(@"completed");
            [subscriber sendCompleted];
        }];
        return nil;
    }];
}
    - (RACSignal *)fetchStationURLListForStation:(NSString *)urlString
    {
        NSURL *url = [NSURL URLWithString:urlString];
        NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
        return [[NSURLConnection rac_sendAsynchronousRequest:urlRequest] map:^(RACTuple *value) {

        // for simplicity i have commented the following method which parses the .pls data to extract the
       // URL List and returing hard coded URL list
       //  return [self processStationURLData:[value second]];
          return @[@"http://66.55.93.205",@"http://66.55.93.205"];
        }];
    }

Output:

2014-01-27 10:49:27.108 Playground[6566:1303] flatten map http://66.55.93.205/listen.pls
2014-01-27 10:49:27.112 Playground[6566:1303] flatten map http://84.20.77.50:8000/listen.pls
2014-01-27 10:49:27.120 Playground[6566:1303] flatten map http://valekalter.serverroom.us:9264/listen.pls
2014-01-27 10:49:27.121 Playground[6566:1303] flatten map http://66.55.93.205:8080/listen.pls
2014-01-27 10:49:27.641 Playground[6566:3603] suscribe next (
    "http://66.55.93.205:80/"
)
2014-01-27 10:49:27.641 Playground[6566:3603] suscribe next (
    "http://66.55.93.205:8080/"
)
2014-01-27 10:50:27.161 Playground[6566:4103] suscribe error Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo=0x8b6efe0 {NSErrorFailingURLStringKey=http://valekalter.serverroom.us:9264/listen.pls, NSErrorFailingURLKey=http://valekalter.serverroom.us:9264/listen.pls, NSLocalizedDescription=The request timed out., NSUnderlyingError=0x8b6e520 "The request timed out."}

I want subscribeNext/Error block to be notified for all the entries in the collection,so that i can mark the entry as valid or invalid.

How to achieve it using reactive cocoa.

UPDATE

I have tried with replacing the subscription block with catch block like below. it catches only the first error event.

- (RACSignal *)processStationList
{
    NSArray *urlList = @[@"http://66.55.93.205/listen.pls",@"http://84.20.77.50:8000/listen.pls",@"http://valekalter.serverroom.us:9264/listen.pls", @"http://66.55.93.205:8080/listen.pls"];

    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [[[urlList.rac_sequence.signal flattenMap:^RACStream *(NSString *urlString) {
            NSLog(@"flatten map %@",urlString);
            return [self fetchStationURLListForStation:urlString];
        }] catch:^RACSignal *(NSError *error) {
            NSLog(@"catch %@",error);
            return [RACSignal empty];
        }] subscribeNext:^(id x) {
            NSLog(@"subscribe next %@",x);
        }];
        return nil;
    }];
}

Output:

2014-01-27 10:55:45.801 Playground[6648:1303] flatten map http://66.55.93.205/listen.pls
2014-01-27 10:55:45.806 Playground[6648:1303] flatten map http://84.20.77.50:8000/listen.pls
2014-01-27 10:55:45.814 Playground[6648:1303] flatten map http://valekalter.serverroom.us:9264/listen.pls
2014-01-27 10:55:45.814 Playground[6648:1303] flatten map http://66.55.93.205:8080/listen.pls
2014-01-27 10:55:46.401 Playground[6648:3603] subscribe next (
    "http://66.55.93.205:8080/"
)
2014-01-27 10:55:46.402 Playground[6648:3603] subscribe next (
    "http://66.55.93.205:80/"
)
2014-01-27 10:55:57.728 Playground[6648:5007] catch Error Domain=NSURLErrorDomain Code=-1004 "Could not connect to the server." UserInfo=0x8b61730 {NSErrorFailingURLStringKey=http://valekalter.serverroom.us:9264/listen.pls, NSErrorFailingURLKey=http://valekalter.serverroom.us:9264/listen.pls, NSLocalizedDescription=Could not connect to the server., NSUnderlyingError=0x8b60f70 "Could not connect to the server."}

How to catch all the errors?

有帮助吗?

解决方案

When your -fetchStationURLListForStation: function calls -sendError: on its subscriber(s), it also ends the signal. The outermost subscriber here catches the error, so the entire outer signal ends as well.

One possibility is to catch errors on your individual inner calls to -fetchStationURLListForStation:.

- (RACSignal *)processStationList
{
    NSArray *urlList = @[@"http://66.55.93.205/listen.pls",@"http://84.20.77.50:8000/listen.pls",@"http://valekalter.serverroom.us:9264/listen.pls", @"http://66.55.93.205:8080/listen.pls"];

    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [[[urlList.rac_sequence.signal flattenMap:^RACStream *(NSString *urlString) {
            NSLog(@"flatten map %@",urlString);
            return [[self fetchStationURLListForStation:urlString]
                   catch:^RACSignal *(NSError *error) {
                       NSLog(@"catch %@",error);
                       return [RACSignal empty];
                   }];
        }]
        subscribeNext:^(id x) {
            NSLog(@"subscribe next %@",x);
        }];
        return nil;
    }];
}

Also, be sure not to reference self within your blocks. Use the @weakify and @strongify macros, or use a weak reference to self that you declare above the return statement.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top