2

我有一种方法可以运行其他几种方法。这些有完成块,我只想在我的每个子方法得到结果后在我的主方法结束时返回一个值。例子:

-(NSMutableDictionary *)mainMethod
{
    [self subMethod1Complete:^(NSMutableArray *results)
    {

    }

    [self subMethod2Complete:^(NSMutableArray *results)
    {

    }

    //return...
}

一旦两个子方法完成,我只想在最后返回我的字典。我怎样才能做到这一点?

我确实有为每个方法存储一个 BOOL 的想法,所以我知道,不完整,是完整的。所以当两者都是YES时,我返回我的字典。但是我怎么能按时而不是过早地调用它呢?

更新

我已经调整了我的代码以使用完成块,因此当我最终从其他方法接收来自另外两个完成块的数据时,我运行带有编译结果的最后一个。下面你可以看到我的方法。你可以在下面看到我的方法,到目前为止没有成功,最终的完成块仍然被过早地调用。

对我来说很重要的一点。getTitlesgetThumbnails方法。在这些的完成块中,我得到了我需要的数据。只有当我拥有这两个时,我才想调用这个 main 方法的最终完成块。因此,一旦收到标题和缩略图,它将传递它们。

-(void)getFeedForUserID:(NSString *)channelID delegate:(id<YTHelperDelegate>)delegate  complete:(void (^)(NSMutableDictionary * result))completionBlock properties:(NSString *)element, ...
{
    va_list args;
    va_start(args, element);

    NSMutableArray *array = [NSMutableArray new];
    for (NSString *arg = element; arg != nil; arg = va_arg(args, NSString *)) [array addObject:arg];

    va_end(args);

    NSMutableDictionary *resultsDict = [NSMutableDictionary new];

    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_t group = dispatch_group_create();

    for (NSString *string in array)
    {
        if ([string isEqualToString:kFeedElementTitle])
        {
            dispatch_group_async(group, queue, ^{
                [self getTitlesArrayForChannel:channelID completionHandler:^(NSMutableArray *results) {
                    dispatch_group_async(group, dispatch_get_main_queue(), ^{
                        [resultsDict setObject:results forKey:kFeedElementTitle];
                    });

                }];
            });
        }
        if ([string isEqualToString:kFeedElementTitle])
        {
            dispatch_group_async(group, queue, ^{
                [self getThumbnailsArrayForChannel:channelID completionHandler:^(NSMutableArray *results) {
                    dispatch_group_async(group, dispatch_get_main_queue(), ^{
                        [resultsDict setObject:results forKey:kFeedElementThumbnail];
                    });
                }];
            });
        }
    }

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        completionBlock(resultsDict);
    });
}
4

3 回答 3

2

您可以使用 GCD 和调度组功能。这是一篇解释它的文章:http ://www.objc.io/issue-2/low-level-concurrency-apis.html#groups

例如,在您的情况下,您的代码可能看起来像这样(从文章中无耻地复制并稍作修改)......

- (void)asyncMethod {
    dispatch_group_t group = dispatch_group_create();

    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_async(group, queue, ^(){
        NSMutableArray * results = [self subMethod1];
        dispatch_group_async(group, dispatch_get_main_queue(), ^(){
            self.subMethod1Results = results;
        });
    });
    dispatch_group_async(group, queue, ^(){
        NSMutableArray * results = [self subMethod2];
        dispatch_group_async(group, dispatch_get_main_queue(), ^(){
            self.subMethod2Results = results;
        });
    });

    // This block will run once everything above is done:
    dispatch_group_notify(group, dispatch_get_main_queue(), ^(){
        // notify the app that both sets of data are ready
        [self notifyWorkIsDone];
        // and release the dispatch group
        dispatch_release(group);
    });
}

这需要对您的类的工作方式进行一些修改,因为上述方法是异步的(这是一件好事——在完成所有工作时它不会阻塞您的应用程序)。您所需要的只是某种处理程序来调用并通知您的应用程序您的数据已准备好,您可以更新您的 UI 或执行任何其他必要的处理。

于 2013-07-16T17:01:28.137 回答
2

您正在寻找 GCD 的dispatch_groupAPI。以下是 Apple并发编程指南中的一些示例代码:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();

// Add a task to the group
dispatch_group_async(group, queue, ^{
   // Some asynchronous work
});

// Do some other work while the tasks execute.

// When you cannot make any more forward progress,
// wait on the group to block the current thread.
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

// Release the group when it is no longer needed.
dispatch_release(group);

对更新代码的评论:

您确定您的错误不是您的第二个if语句kFeedElementTitle第二次检查,而不是kFeedElementThumbnail我认为可能是您想要的吗?


更新了工作示例:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    NSString *kFeedElementTitle = @"some";
    NSString *kFeedElementThumbnail = @"strings";
    NSArray *array = @[@"some", @"test", @"strings"];

    NSMutableDictionary *resultsDict = [NSMutableDictionary new];

    NSLog(@"App launched");

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();

    for (NSString *string in array)
    {
        if ([string isEqualToString:kFeedElementTitle])
        {
            dispatch_group_async(group, queue, ^{
                [NSThread sleepForTimeInterval:5]; // simulate network call

                dispatch_group_async(group, dispatch_get_main_queue(), ^{
                    [resultsDict setObject:@"title result" forKey:kFeedElementTitle];
                    NSLog(@"Received title result");
                });
            });
        }
        if ([string isEqualToString:kFeedElementThumbnail]) // Note: this was changed to kFeedElementThumbnail from kFeedElementTitle
        {
            dispatch_group_async(group, queue, ^{
                [NSThread sleepForTimeInterval:10]; // simulate network call

                dispatch_group_async(group, dispatch_get_main_queue(), ^{
                    [resultsDict setObject:@"thumbnail result" forKey:kFeedElementThumbnail];
                    NSLog(@"Received thumbnail result");
                });
            });
        }
    }

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"final dictionary: %@", resultsDict);
    });


    return YES;
}

输出:

2013-07-16 21:02:46.468 d[947:a0b] App launched
2013-07-16 21:02:51.471 d[947:a0b] Received title result
2013-07-16 21:02:56.471 d[947:a0b] Received thumbnail result
2013-07-16 21:02:56.472 d[947:a0b] final dictionary: {
    some = "title result";
    strings = "thumbnail result";
}
于 2013-07-16T17:01:51.473 回答
-2

您不知道块何时返回,因此您将不知道当时是否有数据,如果我可以建议您在这些块中调用一个方法,该方法将检查是否设置了两个字典如果他们继续这个过程,否则不要继续

- (void)mainMethod
{
    [self subMethod1Complete:^(NSMutableArray *results)
    {
        self.result1 = results;
        [self method3];
    }

    [self subMethod2Complete:^(NSMutableArray *results)
    {
       self.results2 = results;
       [self method3];
    }

}

- (void)method3 {
    if ( self.results1 != nil && self.results2 != nil ) {
         [self startProcedure];
    } else {
         // do nothing
    }

}

尽管我建议您一起修改您的代码以不同的方式执行此操作,只是因为您不能保证其中一个块将在返回时完成,更不用说它们两个

你也可以做这样的事情

-(NSMutableDictionary *)mainMethod
{
    [self subMethod1Complete:^(NSMutableArray *results)
    {

    }

    [self subMethod2Complete:^(NSMutableArray *results)
    {

    }
    while(result == nil)
      sleep(1);

        //return...
    }

这又是真的很糟糕......最好重新编写代码

于 2013-07-16T17:04:35.140 回答