简体   繁体   中英

Reactive cocoa issue.How to wait mutiple RACSignal completed then send a next signal

I'm new to reactive cocoa.I want a signal contain three signal, all the three signal completed then sendNext signal.I have tried concat and then operator.And adjust subscriber next or completed location.It always sendNext signal then execute the three signal in it.Sub is my code.Is there any way to fix it?Or use another way.

- (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. It seems like you're missing the [subscriber sendCompleted] in your third signal, so that one will never complete. It probably belongs outside of the loop right above return nil .

  2. You can use [RACSignal concat@[selectMessageSignal, selectInfoSignal, replaceSignal] to perform these three signals after each other. However , your selectInfoSignal does not work as you might expect because it starts another signal for each value in your contactModelMutableArray but does not wait for these signals completion.

  3. Your code sample is actually much more complex than the question suggests. You have a shared dependency between these signals via the contactModelMutableArray Array thats created outside the signals and manipulated by the signals as a side effect, which you should not do because then the "simple" Solution of just concatenating the signals together will not work reliably as mentioned in 2.

It seems to me that what you're actually doing is:

  1. Select all records (plus some filtering: UID has to be > 0)
  2. Loading information for each of these records
  3. Updating all records

I suggest the following structure (just a rough sketch)

-(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 sends one value with an array of all records. To then process these records individually, we flattenMap this and send one value for each element of the array (using rac_sequence ).

Then its straight forward processing for each record: get infos for that record and then update that records.

The whole replacePubRecentContact signal will complete as soon as all records have been updated.

Edit: I wrote a more detailed explanation in my blog

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM