Инициализация Yin & Yang - дождитесь кусочков перед вызовом init - PullRequest
0 голосов
/ 31 мая 2018

Скажем, у вас есть метод, который возвращает информацию в двух отдельных блоках, например:

@interface SomeObject : NSObject
- (instancetype)initWithA:(NSString *)aInfo bInfo:(NSString *)bInfo;
@end

- (void)someMethod:(void (^)(NSString *aInfo))firstBlock
       secondBlock:(void (^)(NSString *bInfo))secondBlock {
  firstBlock(@"a"); secondBlock(@"b");
}
- (void)ourMethod:(void (^)(SomeObject *object))completionBlock {
  SomeObject *someObject = [[SomeObject alloc] initWithA:aInfo bInfo:bInfo];
  [self someMethod:^(NSString *aInfo) {
    //
  } secondBlock:^(NSString *bInfo) {
    //
  }];
  completionBlock(someObject);
}

Как бы вы инициализировали someObject и передавали его обратно, когда оба блока завершили?

Предположим, что оба блока выполняются асинхронно.

Я попытался поиграться с группами рассылки GCD, чтобы решить эту проблему, однако это не показалось оптимальным.

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

Поскольку вам нужно создать someObject со значениями, полученными из двух блоков, используемых при вызове someMethod, вам необходимо создать someObject после того, как оба блока были вызваны.

- (void)ourMethod:(void (^)(BOOL initializationComplete))completionBlock {
    __block NSString *a = nil;
    __block NSString *b = nil;

    dispatch_group_t group = dispatch_group_create();
    dispatch_group_enter(group);
    dispatch_group_enter(group);

    [self someMethod:^(NSString *aInfo) {
        a = aInfo;
        dispatch_group_leave(group);
    } secondBlock:^(NSString *bInfo) {
        b = bInfo;
        dispatch_group_leave(group);
    }];

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        SomeObject *someObject = [[SomeObject alloc] initWithA:a bInfo:b];
        completionBlock(someObject);
    });
}

Это не блокирует вызывающего ourMethod и гарантирует, что блок завершения вызывается только после завершения обоих блоков.

В этом решении предполагается, что два блока выполняются асинхронно.

0 голосов
/ 31 мая 2018

Вы можете использовать семафор, но - в общем - синхронизация асинхронной операции - это красный флаг, указывающий на плохой дизайн.

Являются ли два блока асинхронными сами по себе?Если это так, вы могли бы иметь __block BOOL firstDone = NO; и __block BOOL secondDone = NO; и соответственно проверить, настало ли время для вызова блока завершения.Все еще безобразно, и вам понадобится примитив синхронизации, чтобы убедиться, что вы не участвуете в гонке, но это бы сработало.

Если firstBlock() и secondBlock() синхронны и находятся в одной очереди,затем просто позвоните completionBlock() после завершения второго.

Или, в качестве альтернативы, если они асинхронные и одновременно запланированы, бросьте их в асинхронную очередь, а затем бросьте барьерный блок в очередь, которая вызывает completionBlock.

...