如何同时执行多个异步方法并在它们全部完成后获得回调?

时间:2015-10-09 20:20:26

标签: ios objective-c swift asynchronous grand-central-dispatch

我编写了以下内容,但我不确定它是否按照预期的方式运行:

func loadAssets(assets: [String: [String]]) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0) {
        let group = dispatch_group_create()
        for (assetType, ids) in assets {
            switch(assetType) {
            case Settings.imageAssetType:
                for id in ids {
                    dispatch_group_enter(group)
                    Assets.fetchImage(id) { _ in
                        dispatch_group_leave(group)
                    }
                }
            case Settings.soundAssetType:
                for id in ids {
                    dispatch_group_enter(group)
                    Assets.fetchSound(id) { _ in
                        dispatch_group_leave(group)
                    }
                }
            case Settings.jsonAssetType:
                for id in ids {
                    dispatch_group_enter(group)
                    Assets.fetchJSON(id) { _ in
                        dispatch_group_leave(group)
                    }
                }
            case default:
                for id in ids {
                    dispatch_group_enter(group)
                    Assets.fetchClip(id) { _ in
                        dispatch_group_leave(group)
                    }
                }
            }
        }
        dispatch_group_notify(group, main, self.assetsDidLoad)
    }
}

基本上,这是一种使用Dictionary加载所有一堆资产的方法,其中键值包含其键中的资产类型和资产ID列表作为值。然后,我为每种类型的资产迭代所有这些资产ID,并调用获取资产的方法。 (我不确定fetch方法是否异步完全运行,它们可能同步部分代码,这些方法将加载资源)。​​

无论如何,我想要做的是在所有这些获取方法完成后调用方法assetsDidLoad(),因此,所有资产都已加载,这就是我尝试使用调度组功能的原因。但是,我对这个调度代码很陌生,我不确定我现在做的是否适用于我的目的。

如果有人能指出这是否合适,或者我应该接近这个方式,我将不胜感激。我甚至很欣赏Objective-C中的回复。

谢谢!

1 个答案:

答案 0 :(得分:3)

您的代码看起来是正确的(假设您的所有<?php $pageT = "View Ticket"; require_once("core/inc.php"); $ID = strip_tags(htmlentities($_GET['ID'])); $db = new DB(); $Config = new Config; $User = new User; $Organize = new Organize; $Ticket = $db->fetchRow( 'SELECT * FROM tickets WHERE ID = :id', [':id' => $ID] ); $TR = $db->fetchRow( 'SELECT * FROM ticket_replies WHERE TID = :tid', [':tid' => $ID] ); $Poster = $db->fetchRow( 'SELECT * FROM users WHERE UID = :poster', [':poster' => $Ticket['Poster']] ); $Replier = $db->fetchRow( 'SELECT * FROM users WHERE UID = :poster', [':poster' => $TR['Poster']] ); if($Ticket == 0) { echo "Sorry, but this is an unkown ticket."; require_once("modules/design/footer.ris.php"); die(); } /* if($User->Info('UID') !== $Ticket['Poster']) { if($User->Info('Rank') !== "Support" || $User->Info('Rank') !== "Admin" || $User->Info('Rank') !== "Admin") { echo "Nice try, this is not your ticket. ;("; require_once("modules/design/footer.ris.php"); die(); } } */ echo ' <div class="row"> <div class="col-md-8 col-lg-9"> <div class="panel panel-default m-t-20"> <div class="panel-heading"> <h3 class="panel-title"> <span class="label label-warning"> '.strip_tags(htmlentities($Ticket['Priority'])).'</span> &nbsp; &nbsp; <span class="label label-primary"> '.strip_tags(htmlentities($Ticket['Dept'])).'</span> '.strip_tags(htmlentities($Ticket['Title'])).''; if($User->Info('Rank') == "Admin" || $User->Info('Rank') == "Owner") { echo "<a style='float:right;margin-left:5px;'class='btn btn-icon waves-effect waves-light btn-danger m-b-5' href=''>Delete Ticket</a> <a style='float:right;margin-left:5px;'class='btn btn-icon waves-effect waves-light btn-info m-b-5' href=''>View Logs</a> &nbsp; <a style='float:right;' class='btn btn-icon waves-effect waves-light btn-info m-b-5' href='AP_EditUser?UID=".$Poster['UID']."'>Edit User</a> &nbsp;"; } echo '</h3> </div> <div class="panel-body"> <div class="media m-b-30"> <div class="media-body"><span class="media-meta pull-right">'.strip_tags(htmlentities($Organize->timeElapsedFromUNIX($Ticket['Date']))).'</span> <h4 class="text-primary m-0"><u>'.strip_tags(htmlentities($Poster['Username'])).'</u></h4> </div> </div> <p> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '.strip_tags(htmlentities($Ticket['Details'])).' </p> </div> </div> '; foreach ($TR as $Reply) { if($Replier['Rank'] == "Support" || $Replier['Rank'] == "Admin" || $Replier['Rank'] == "Owner") { echo ' <div style="border-top:4px solid red;" class="panel panel-default m-t-20"> <div class="panel-body"> <div class="media m-b-30"> <div class="media-body"><span class="media-meta pull-right">'.strip_tags(htmlentities($Organize->timeElapsedFromUNIX($Reply['Date']))).'</span> <h4 class="text-primary m-0">'.strip_tags(htmlentities($Replier['Username'])).'</h4> <small>'.$Replier['Rank'].'</small> </div> </div> <p> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '.$Organize->showBBcodes($Reply['Content']).' </p> </div> </div> '; } else { echo ' <div style="border-top:4px solid #CCC;" class="panel panel-default m-t-20"> <div class="panel-body"> <div class="media m-b-30"> <div class="media-body"><span class="media-meta pull-right">'.strip_tags(htmlentities($Organize->timeElapsedFromUNIX($TR['Date']))).'</span> <h4 class="text-primary m-0">'.strip_tags(htmlentities($Replier['Username'])).'</h4> <small>'.$Replier['Rank'].'</small> </div> </div> <p> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '.strip_tags(htmlentities($Reply['Details'])).' </p> </div> </div> '; } break; } echo ' <div class="panel panel-default"> <div class="panel-body"> <div class="media"> <form role="form" method="POST"> <div class="media-body"> <textarea class="wysihtml5 form-control" id="replyDetails" name="replyDetails" rows="9" placeholder="Reply here..."></textarea> </div> </div> <div class="text-right"> <button type="submit" id="addReply" name="addReply" class="btn btn-primary waves-effect waves-light m-t-30 w-md">Send Reply</button> </div> </form> </div> </div> </div> </div> </div> </div> '; if(isset($_POST['addReply'])) { $Details = strip_tags(htmlentities($_POST['replyDetails'])); if(empty($Details)) { echo '<div class="col-md-8"><div class="alert alert-danger"><strong>Could not send reply :</strong> <br /> &bullet; You forgot a field or two. Please try again.</div></div>'; } elseif(strlen($Details) > 700) { echo '<div class="col-md-8"><div class="alert alert-danger"><strong>Could not send reply :</strong> <br /> &bullet; You cannot exeed 700 characters. Please try again.</div></div>'; } else { $Values = [ 'TID' => $ID, 'Poster' => $User->Info('UID'), 'Content' => $Details, 'Date' => time() ]; $insertValues = $db->insert('ticket_replies')->values($Values); $Values2 = [ 'Username' => $User->Info('Username'), 'UID' => $User->Info('UID'), 'IP' => $Logs->IP(), 'Platform' => $Logs->Browser(), 'Type' => '8', 'Value' => 'Replied to a ticket.', 'Date' => $Logs->Date(), ]; $insertValues2 = $db->insert('logs')->values($Values2); } } 方法都保证执行其块)。如果fetch为空,则会立即触发通知块。 assetsdispatch_group_enter只需要平衡,就可以在队列中调用。

作为参考,这里是我用来测试一些不同情况的一些代码(在Objective-C中):

dispatch_group_leave

哪一端显示警报,在调试器中显示:

dispatch_queue_t queue = dispatch_queue_create("com.Test.TestQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, queue, ^
{
    sleep(3);
    printf("\nFirst done!");
});

dispatch_group_async(group, queue, ^
{
    sleep(1);
    printf("\nSecond done!");

    dispatch_group_enter(group);
    sleep(5);
    printf("\nNested done!");
    dispatch_group_leave(group);

});

dispatch_group_async(group, queue, ^
{
    sleep(2);
    printf("\nThird done!");
});

dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
{
    sleep(10);
    printf("\nAsync done!");
    dispatch_group_leave(group);
});

dispatch_group_notify(group, dispatch_get_main_queue(), ^
{
    printf("\nAll done!");

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Title" message:@"Message" delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:nil];
    [alertView show];
});