GCD用于简单下载队列

时间:2017-01-29 20:14:52

标签: swift asynchronous grand-central-dispatch

我想创建一个简单的下载队列,我不需要太多功能,只需要一个串行队列,这样当我运行我的下载过程时,它将等待第一次下载完成后再开始第二次下载。我使用parse-server运行它的查询并在后台获取数据函数,但它似乎同时运行。

我在考虑使用GCD,因为当解析服务器功能正在处理时,我没有直接看到需要使用创建NSURL会话来下载我的文件。

为此我定义了一个队列:

let downloadQueue = DispatchQueue(label: "downloadQueue", qos: .background)

然后认为将我的下载功能包装在此队列中会将要下载的项目添加到队列的后面。但是,这似乎不会发生,文件一旦被选中就开始下载。

func downloadDataToDevice(cell: JourneyCollectionViewCell, selectedIndexPath: IndexPath){

    self.downloadQueue.async {

        // query and progressBlock to track download progress
    }
}

1 个答案:

答案 0 :(得分:1)

创建DispatchQueue

为了确定问题的原因,我们需要更详细一些。首先,您创建的dispatchQueueserial队列。这意味着添加到队列的任何块都将以串行方式执行。 GCD不保证这些执行的时间,只保证它们的执行顺序。请记住,GCD没有指定您的代码将在哪个线程上执行,只是它将服务质量视为.background

添加块

现在,在向串行队列添加代码块时,可以调用队列中的.sync.async方法。这些分类器确定您添加到队列的代码块是否将相对于当前线程执行同步或异步。因此,如果您向队列添加代码块.sync,GCD将阻止当前线程,直到代码执行完毕。如果向队列添加代码块.async,则当前线程将根据GCD的判断继续执行。无论您是否向其添加代码块DispatchQueue.sync.async本身仍然是一个串行队列。

执行块

现在开始你的Parse代码,因为这可能会变得有点棘手。我们已确定您的DispatchQueueserial队列。但是,假设您在队列中添加了一个代码块,它在后台执行某些操作(例如下载文件)并具有一些回调函数。从DispatchQueue和运行代码块的线程的角度来看,一旦启动后台操作,这段代码就完成了执行,它将继续运行到下一个块在队列中。这是一个澄清一点的例子:

downloadQueue.async {
    Parse.doSomethingAsync("something", callback: {(error: Error) in
        // Do something else ...
    }
}

正如您在此处所看到的,当GCD执行此代码块时,doSomethingAsync方法将根据Parse API实现该方法的方式运行后台。如果我没有弄错的话,解析API对同步或异步行为有不同的功能。一旦doSomethingAsync被调用并在后台开始执行,这段代码就完成了执行,然后GCD可以开始执行下一个代码块...即使从您的角度来看代码还没有完成后,因为文件未完成下载。 以下代码不会遇到此问题:

downloadQueue.async {
    Parse.doSomethingSync("something", callback: {(error: Error) in
        // Do something else ...
    }
}

因为doSomethingSync将对当前线程执行相对于块的操作,并且块将停止执行,直到它完成执行doSomethingSync方法。

TLDR和更多信息

TLDR;您需要确保GCD块中的下载操作是串行的,并在下载发生时阻止执行。

本教程详细介绍了GCD:https://www.raywenderlich.com/60749/grand-central-dispatch-in-depth-part-1