寻找最优雅的方法来链接依赖的网络请求树与反应可可?

时间:2014-03-11 14:22:36

标签: ios reactive-cocoa

This is the solution from my last question:

由于我不熟悉reactiveCocoa,我有点不确定这是否是正确的方法?

基本上我想让我的依赖网络请求一个接一个地被序列化。

他们形成一棵树,所以先发送父母,然后发送任何孩子,然后是下一位父母:

在做了一些测试之后,下面的代码似乎完全符合我的要求: 如果我以正确的方式使用reactiveCocoa,有人可以告诉我吗? 我可以遇到死锁吗?

#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>

@interface ViewController () {
    dispatch_queue_t backgroundQueue;
}
@end

@implementation ViewController
/**
 simulating network requests
 */

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

         dispatch_async(backgroundQueue, ^(void) {
             NSLog(@"  saving depending %@ ",ctx);
             [subscriber sendCompleted];
         });

         return nil;
      }];
}
/**
 simulating network requests
 */
-(RACSignal*) executeRequestAsynchChildStep:(NSString*) ctx withParent:(NSString *) parent {
    return [RACSignal createSignal:^RACDisposable * (id<RACSubscriber> subscriber) {

        dispatch_async(backgroundQueue, ^(void) {
            NSLog(@"  saving depending ChildStep %@ of parent step:%@",ctx,parent);
            [subscriber sendCompleted];
        });

        return nil;
    }];

}

-(RACSignal*) executeRequestAsynch2:(NSString*) parent {
    RACSignal *contexts = [[@[ @"ChildStep 1", @"ChildStep 2",@"ChildStep 3", @"ChildStep 4"] rac_sequence] signalWithScheduler:RACScheduler.immediateScheduler];
    contexts = [contexts map:^(id ctx) {
        return [self executeRequestAsynchChildStep:ctx withParent:parent];
    }];
    return [contexts concat];

}
- (void)viewDidLoad
{
    [super viewDidLoad];
    backgroundQueue = dispatch_queue_create("blah", NULL);
    RACSignal *contexts = [[@[ @"Step 1", @"Step 2",@"Step 3", @"Step 4",@"Step 5", @"Step 6"] rac_sequence] signalWithScheduler:RACScheduler.immediateScheduler];
    RACSignal *ne = [[contexts map:^(id ctx) {
        NSLog(@"iterating map  %@",ctx);
        return [[self executeRequestAsynch:ctx] concat: [self executeRequestAsynch2:ctx ]];
        }]concat] ;
    [ne subscribeCompleted:^{
        NSLog(@"done all");
    }];
}


@end

输出是:

2014-03-11 15:06:23.361 test[2470:70b] iterating map  Step 1
2014-03-11 15:06:23.362 test[2470:70b] iterating map  Step 2
2014-03-11 15:06:23.362 test[2470:1303]   saving depending Step 1 
2014-03-11 15:06:23.363 test[2470:70b] iterating map  Step 3
2014-03-11 15:06:23.363 test[2470:1303]   saving depending ChildStep ChildStep 1 of parent step:Step 1
2014-03-11 15:06:23.363 test[2470:70b] iterating map  Step 4
2014-03-11 15:06:23.363 test[2470:70b] iterating map  Step 5
2014-03-11 15:06:23.363 test[2470:1303]   saving depending ChildStep ChildStep 2 of parent step:Step 1
2014-03-11 15:06:23.364 test[2470:70b] iterating map  Step 6
2014-03-11 15:06:23.364 test[2470:1303]   saving depending ChildStep ChildStep 3 of parent step:Step 1
2014-03-11 15:06:23.364 test[2470:1303]   saving depending ChildStep ChildStep 4 of parent step:Step 1
2014-03-11 15:06:23.365 test[2470:1303]   saving depending Step 2 
2014-03-11 15:06:23.365 test[2470:1303]   saving depending ChildStep ChildStep 1 of parent step:Step 2
2014-03-11 15:06:23.365 test[2470:1303]   saving depending ChildStep ChildStep 2 of parent step:Step 2
2014-03-11 15:06:23.370 test[2470:1303]   saving depending ChildStep ChildStep 3 of parent step:Step 2
2014-03-11 15:06:23.370 test[2470:1303]   saving depending ChildStep ChildStep 4 of parent step:Step 2
2014-03-11 15:06:23.370 test[2470:1303]   saving depending Step 3 
2014-03-11 15:06:23.371 test[2470:1303]   saving depending ChildStep ChildStep 1 of parent step:Step 3
2014-03-11 15:06:23.371 test[2470:1303]   saving depending ChildStep ChildStep 2 of parent step:Step 3
2014-03-11 15:06:23.372 test[2470:1303]   saving depending ChildStep ChildStep 3 of parent step:Step 3
2014-03-11 15:06:23.372 test[2470:1303]   saving depending ChildStep ChildStep 4 of parent step:Step 3
2014-03-11 15:06:23.372 test[2470:3803]   saving depending Step 4 
2014-03-11 15:06:23.373 test[2470:3503]   saving depending ChildStep ChildStep 1 of parent step:Step 4
2014-03-11 15:06:23.373 test[2470:3803]   saving depending ChildStep ChildStep 2 of parent step:Step 4
2014-03-11 15:06:23.373 test[2470:3503]   saving depending ChildStep ChildStep 3 of parent step:Step 4
2014-03-11 15:06:23.401 test[2470:3503]   saving depending ChildStep ChildStep 4 of parent step:Step 4
2014-03-11 15:06:23.402 test[2470:3503]   saving depending Step 5 
2014-03-11 15:06:23.402 test[2470:3503]   saving depending ChildStep ChildStep 1 of parent step:Step 5
2014-03-11 15:06:23.402 test[2470:3503]   saving depending ChildStep ChildStep 2 of parent step:Step 5
2014-03-11 15:06:23.403 test[2470:3503]   saving depending ChildStep ChildStep 3 of parent step:Step 5
2014-03-11 15:06:23.403 test[2470:3503]   saving depending ChildStep ChildStep 4 of parent step:Step 5
2014-03-11 15:06:23.404 test[2470:3503]   saving depending Step 6 
2014-03-11 15:06:23.404 test[2470:3503]   saving depending ChildStep ChildStep 1 of parent step:Step 6
2014-03-11 15:06:23.405 test[2470:3503]   saving depending ChildStep ChildStep 2 of parent step:Step 6
2014-03-11 15:06:23.405 test[2470:3503]   saving depending ChildStep ChildStep 3 of parent step:Step 6
2014-03-11 15:06:23.405 test[2470:3503]   saving depending ChildStep ChildStep 4 of parent step:Step 6
2014-03-11 15:06:23.406 test[2470:3503] done all

在考虑了建议的更改后,我得到了以下代码:

    #import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>

@interface ViewController () {
    dispatch_queue_t backgroundQueue;
}
@end

@implementation ViewController
/**
 simulating network requests
 */
-(RACSignal*) executeRequestAsynch:(NSString*) ctx {
     return [RACSignal createSignal:^RACDisposable * (id<RACSubscriber> subscriber) {

         dispatch_async(backgroundQueue, ^(void) {
             //simulating URLConnnection network requests with completion handler
             NSLog(@"  saving depending %@ ",ctx);
             [subscriber sendCompleted];
         });
         return nil;
      }];
}
/**
 simulating network requests
 */
-(RACSignal*) executeRequestAsynchChildStep:(NSString*) ctx withParent:(NSString *) parent {
    return [RACSignal createSignal:^RACDisposable * (id<RACSubscriber> subscriber) {

        dispatch_async(backgroundQueue, ^(void) {
            //simulating URLConnnection network requests with completion handler
            NSLog(@"  saving depending ChildStep %@ of parent step:%@",ctx,parent);
            [subscriber sendCompleted];
        });
        return nil;
    }];

}
-(RACSignal*) executeRequestAsynch2:(NSString*) parent {
    RACSequence *contexts = [@[ @"ChildStep 1", @"ChildStep 2",@"ChildStep 3", @"ChildStep 4"] rac_sequence];
    contexts = [contexts map:^(id ctx) {
        return [self executeRequestAsynchChildStep:ctx withParent:parent];
    }];
    return [RACSignal concat:contexts];

}

- (void)viewDidLoad
{
    [super viewDidLoad];
    backgroundQueue = dispatch_queue_create("blah", NULL);
    RACSignal *contexts = [[@[ @"Step 1", @"Step 2",@"Step 3", @"Step 4"] rac_sequence] signal];
    RACSignal *ne = [[contexts map:^(id ctx) {
        NSLog(@"iterating map  %@",ctx);
        return [[self executeRequestAsynch:ctx] concat: [self executeRequestAsynch2:ctx ]];
        }]concat] ;
    [ne subscribeCompleted:^{
        NSLog(@"done all");
    }];
}

1 个答案:

答案 0 :(得分:1)

总的来说,看起来好像代码可以做你想做的事情。我没有看到任何引起关注僵局的原因。您认为某个特定区域可能会陷入僵局吗?

我可以就代码给你一些建议。

您已经清楚地看到ReactiveCocoa具有调度程序(RACScheduler)的概念,并且此类允许您替换调度队列的命令式使用。以上信号:

return [RACSignal createSignal:^(id<RACSubscriber> subscriber) {
    dispatch_async(backgroundQueue, ^{
        NSLog(@"  saving depending ChildStep %@ of parent step:%@", ctx, parent);
        [subscriber sendCompleted];
    });
    return nil;
}];

可以使用-subscribeOn:重写:

RACScheduler *backgroundScheduler = [[RACScheduler alloc] initWithName:nil targetQueue:backgroundQueue];

return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
    NSLog(@"  saving depending ChildStep %@ of parent step:%@", ctx, parent);
    [subscriber sendCompleted];
    return nil;
}] subscribeOn:backgroundScheduler];

接下来,您可以简化您使用序列的方式。您可以将序列传递给+[RACSignal concat:],而不是将序列转换为信号。例如,而不是:

RACSignal *contexts = [[@[@"ChildStep 1", … @"ChildStep N"] rac_sequence] signalWithScheduler:RACScheduler.immediateScheduler];
contexts = [contexts map:^(id ctx) {
    return [self executeRequestAsynchChildStep:ctx withParent:parent];
}];
return [contexts concat];

您可以放弃-signalWithScheduler:的使用,并应用+concat:

RACSequence *contexts = [@[@"ChildStep 1", … @"ChildStep N"] rac_sequence];
contexts = [contexts map:^(id ctx) {
    return [self executeRequestAsynchChildStep:ctx withParent:parent];
}];
return [RACSignal concat:contexts];

希望有所帮助。

PS。你可以通过following the ReactiveCocoa discussions学到很多东西。