简体   繁体   English

等待Objective-C中的异步操作

[英]Wait for Asynchronous Operations in Objective-C

I'm googling like crazy and still confused about this. 我谷歌搜索疯狂,仍然对此感到困惑。

I want to download an array of file urls to disk, and I want to update my view based on the bytes loaded of each file as they download. 我想将一个文件URL数组下载到磁盘,我想根据下载时每个文件加载的字节更新我的视图。 I already have something that will download a file, and report progress and completion via blocks. 我已经有了下载文件的东西,并通过块报告进度和完成情况。

How can I do this for each file in the array? 如何为阵列中的每个文件执行此操作?

I'm ok doing them one at a time. 我可以一次做一个。 I can calculate the total progress easily that way: 我可以通过这种方式轻松计算总进度:

float progress = (numCompletedFiles + (currentDownloadedBytes / currentTotalBytes)) / totalFiles)

I mostly understand GCD and NSOperations, but how can you tell an operation or dispatch_async block to wait until a callback is called before being done? 我主要理解GCD和NSOperations,但是如何告诉操作或dispatch_async块在完成之前等待回调? It seems possible by overriding NSOperation, but that seems like overkill. 似乎有可能通过覆盖NSOperation,但这似乎有点矫枉过正。 Is there another way? 还有另外一种方法吗? Is it possible with just GCD? 只有GCD才有可能吗?

I'm not sure if I understand you correctly, but perhaps you need dispatch semaphores to achieve your goal. 我不确定我是否理解正确,但也许你需要派遣信号量来实现你的目标。 In one of my projects I use a dispatch semaphore to wait until another turn by another player is completed. 在我的一个项目中,我使用调度信号量等待另一个玩家完成另一个转弯。 This is partially the code I used. 这部分是我使用的代码。

for (int i = 0; i < _players.count; i++)
{

    // a semaphore is used to prevent execution until the asynchronous task is completed ...

    dispatch_semaphore_t sema = dispatch_semaphore_create(0);


    // player chooses a card - once card is chosen, animate choice by moving card to center of board ...

    [self.currentPlayer playCardWithPlayedCards:_currentTrick.cards trumpSuit:_trumpSuit completionHandler:^ (WSCard *card) {

        BOOL success = [self.currentTrick addCard:card];

        DLog(@"did add card to trick? %@", success ? @"YES" : @"NO");

        NSString *message = [NSString stringWithFormat:@"Card played by %@", _currentPlayer.name];
        [_messageView setMessage:message];

        [self turnCard:card];
        [self moveCardToCenter:card];


        // send a signal that indicates that this asynchronous task is completed ...

        dispatch_semaphore_signal(sema);

        DLog(@"<<< signal dispatched >>>");
    }];


    // execution is halted, until a signal is received from another thread ...

    DLog(@"<<< wait for signal >>>");

    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    dispatch_release(sema);


    DLog(@"<<< signal received >>>");

dispatch groups are the GCD facility designed to track completion of a set of independent or separately async'd blocks/tasks. 调度组是GCD工具,用于跟踪一组独立或单独异步的块/任务的完成情况。

Either use dispatch_group_async() to submit the blocks in question, or dispatch_group_enter() the group before triggering the asynchronous task and dispatch_group_leave() the group when the task has completed. 使用dispatch_group_async()提交有问题的块,或者在触发异步任务之前使用dispatch_group_enter()组,并在任务完成时使用dispatch_group_leave()组。

You can then either get notified asynchronously via dispatch_group_notify() when all blocks/tasks in the group have completed, or if you must, you can synchronously wait for completion with dispatch_group_wait(). 然后,当组中的所有块/任务完成时,您可以通过dispatch_group_notify()异步通知,或者如果必须,您可以使用dispatch_group_wait()同步等待完成。

I just wanted to note that I did get it working by subclassing NSOperation and making it a "concurrent" operation. 我只想注意,我确实通过继承NSOperation并使其成为“并发”操作来实现它。 (Concurrent in this context means an async operation that it should wait for before marking it as complete). (此上下文中的并发意味着在将其标记为完成之前应等待的异步操作)。

http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/ http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/

Basically, you do the following in your subclass 基本上,您在子类中执行以下操作

  1. override start to begin your operation 覆盖start开始您的操作
  2. override isConcurrent to return YES override isConcurrent返回YES
  3. when you finish, make sure isExecuting and isFinished change to be correct, in a key-value compliant manner (basically, call willChangeValueForKey: and didChangeValueForKey: for isFinished and isExecuting 完成后,确保isExecuting和isFinished更改为正确,符合键值方式(基本上,调用willChangeValueForKey:didChangeValueForKey: for isFinished and isExecuting

And in the class containing the queue 并在包含队列的类中

  1. set the maxConcurrentOperationCount on the NSOperationQueue to 1 maxConcurrentOperationCount上的NSOperationQueue1
  2. add an operation after all your concurrent ones which will be triggered once they are all done 在所有并发的操作之后添加一个操作,一旦完成它们就会被触发

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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