反应性可可问题。如何等待多个RACSignal完成然后发送下一个信号

时间:2018-02-12 07:56:31

标签: ios objective-c iphone reactive-programming reactive-cocoa

我是反应性可可的新手。我想要一个信号包含三个信号,所有三个信号都完成然后发送下一个信号。我尝试了concat然后运营商。然后调整用户下一个或完成位置。它总是发送下一个信号然后执行它中的三个信号。我是我的代码。有什么方法可以解决它吗?或者用另一种方式。

- (RACSignal *)replacePubRecentContact {
@weakify(self);
return [RACSignal createSignal:^RACDisposable *(id <RACSubscriber> subscriber) {
    NSMutableArray <RIMRecentContactModel *> *contactModelMutableArray = [NSMutableArray new];
    //1 Signal first
    RACSignal *selectMessageSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [[[RIMPublicPostDatabaseManager sharedInstance] selectLastMessage] subscribeNext:^(NSArray <RIMRecentContactModel *> *pubContactModelArray) {
            //这里穿回来的lastmMessage是一个pmsgId
            for (NSUInteger i = 0; i < pubContactModelArray.count; ++i) {
                if (pubContactModelArray[i].uid > 0) {
                    [contactModelMutableArray addObject:pubContactModelArray[i]];
                }
            }
            [subscriber sendNext:@"pub replace select last message bingo"];
            [subscriber sendCompleted];
        }];
        return nil;
    }];


    //2 Signal second
    RACSignal *selectInfoSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        @strongify(self);
        for (NSUInteger j = 0; j < contactModelMutableArray.count; ++j) {
            @strongify(self);

            [[self selectPubInfoWithPid:contactModelMutableArray[j].uid] subscribeNext:^(RIMPubInfoModel *pubInfoModel) {
                contactModelMutableArray[j].username = pubInfoModel.name;
                contactModelMutableArray[j].avatar = pubInfoModel.logo;
            }];
        }
        [subscriber sendNext:@"pub replace select info bingo"];
        [subscriber sendCompleted];
        return nil;
    }];

    //3 Signal third
    RACSignal *replaceSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [self.contactDatabaseQueue inDatabase:^(FMDatabase *db) {
            for (NSUInteger k = 0; k < contactModelMutableArray.count; ++k) {
                RIMRecentContactModel *recentContactModel = contactModelMutableArray[k];
                //公众号type 3
                recentContactModel.messageType = 3;

                NSString *replaceSql = [NSString stringWithFormat:@"REPLACE INTO  recentContact (uid, username, avatar, lastMessage, unRead, lastMessageTs, messageType, lastMessageMid, lastMessageSid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"];
                //这里因为私聊公众号id重复所以加3
                BOOL result = [db executeUpdate:replaceSql, @(recentContactModel.uid), recentContactModel.username, recentContactModel.avatar, recentContactModel.lastMessage, @(recentContactModel.unRead), @(recentContactModel.lastMessageTs), @(recentContactModel.messageType), @(recentContactModel.lastMessageMid), @(recentContactModel.lastMessageSid)];
                if (!result) {
                    NSLog(@"插入最近联系人表失败");
                } else {
                    NSLog(@"插入最近联系人表成功");
                }
            }
            [subscriber sendNext:@"replace公众号最近联系人表成功"];

        }];
        return nil;
    }];
    [[[selectMessageSignal concat:selectInfoSignal] then:^RACSignal *{
        return replaceSignal;
    }] subscribeCompleted:^{
    }];
    [subscriber sendNext:@"replace pub all bingo"];
    [subscriber sendCompleted];
    return nil;
}];

}

1 个答案:

答案 0 :(得分:0)

  1. 您似乎错过了第三个信号中的[subscriber sendCompleted],因此永远无法完成。{li>

    它可能属于return nil正上方的循环之外。

  2. 您可以使用[RACSignal concat@[selectMessageSignal, selectInfoSignal, replaceSignal]相互执行这三个信号。 但是,您的selectInfoSignal无法正常工作,因为它会为contactModelMutableArray中的每个值启动另一个信号,但不会等待这些信号完成。

  3. 您的代码示例实际上比问题建议的要复杂得多。通过在信号外部创建的contactModelMutableArray数组和信号操作作为副作用,您在这些信号之间具有共享依赖关系,这是您不应该做的,因为那时简单的&#34;如2中所述,将信号连接在一起的解决方案将无法可靠地工作。

  4. 在我看来,你实际做的是:

    1. 选择所有记录(加上一些过滤:UID必须> 0)
    2. 加载每条记录的信息
    3. 更新所有记录
    4. 我建议使用以下结构(只是草图)

      -(RACSignal *)replacePubRecentContact {
        return [[[[self loadRecords] flattenMap:^RACSignal *(NSArray *records) {
          return [[records rac_sequence] signal];
        }] flattenMap:^RACSignal *(id  record) {
          return [self infosForRecord:record];
        }] flattenMap:^RACSignal * (id record) {
          return [self updateRecord:record];
        }];
      }
      
      // This function loads all records
      -(RACSignal *)loadRecords {
        NSLog(@"Return all Records");
        return [RACSignal return:@[@1, @2, @3]];
      }
      
      // This function load infos for the given record
      -(RACSignal *)infosForRecord:(id)record {
        NSLog(@"Load Infos for Record %@", record);
        return [RACSignal return:[NSString stringWithFormat: @"%@ with info", record]];
      }
      
      // This function updates the given record
      -(RACSignal *)updateRecord:(id)record {
        NSLog(@"Update Record: %@", record);
        return [RACSignal return:[NSString stringWithFormat: @"Updated - %@", record]];
      }
      

      loadRecords使用所有记录的数组发送一个值。为了然后单独处理这些记录,我们flattenMap这个并为数组的每个元素发送一个值(使用rac_sequence)。

      然后对每条记录进行直接处理:获取该记录的信息,然后更新该记录。

      只要所有记录更新,整个replacePubRecentContact信号就会完整。

      编辑:我写了更详细的解释in my blog