ios - NSURLSession 任务文件下载发生在程序需要使用该文件之后

标签 ios swift grand-central-dispatch nsurlsession

我定义了一个带有下载任务的 NSURLSession。我想下载一个文件,然后在我的绘图样式工具包中使用文件中的值。 session 和绘图样式工具包确实在同步队列上运行,不幸的是,任务在 NSOperationQueue 上运行,该队列在创建 View 后才运行。因此, View 不包含正确的文件信息。是否有编码解决方案或者它是一个逻辑问题,是否有人对改进逻辑有建议。我是新手,欢迎提出任何建议。

class SomeView: UIView, NSURLSessionDelegate, NSURLSessionTaskDelegate

{
var session: NSURLSession!

required init(coder aDecoder: NSCoder)
{
    super.init(coder: aDecoder)

    // Create the session configuration
    let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
    configuration.timeoutIntervalForRequest = 15.0

    // Create the session
    session = NSURLSession(configuration: configuration,
        delegate: self,
        delegateQueue: nil)
}



override func drawRect(rect: CGRect)
{
    let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)


        dispatch_sync(queue,
            {
                // Define the data source at www.powerball.com/powerball/winnums-text.txt
                let url = NSURL(string: "http://www.powerball.com/powerball/winnums-text.txt")

                // Create the download task for the session

                let task = self.session.downloadTaskWithURL(url!, completionHandler:
                    {[weak self] (url: NSURL!,
                        response: NSURLResponse!,
                        error: NSError!) in

                        if error == nil
                        {
                            let fileManager = NSFileManager()


                            //Get the path for the caches folder
                            var error: NSError?
                            var cachePath = fileManager.URLForDirectory(
                                NSSearchPathDirectory.CachesDirectory,
                                inDomain: NSSearchPathDomainMask.UserDomainMask,
                                appropriateForURL: url,
                                create: true,
                                error: &error)!


                            // Assign consistent file name
                            var fileName = "winnums-text"

                            // Apend the file name to the cache path
                            var filePath = cachePath.URLByAppendingPathComponent(fileName)

                            // Move the file to the file path
                            fileManager.moveItemAtURL(url, toURL: filePath, error: nil)

                            println(filePath)
                        }
                        else
                        {
                            println("Connection failed")  //add user notification later
                        }

                        //Clean up sessions
                        self!.session.finishTasksAndInvalidate()
                })  //Task
                task.resume()
            })  // Dispatch queue

        dispatch_sync(queue,
            {
                    // Only override drawRect: if you perform custom drawing.
                    SomeappStyleKit.drawMain(frame: self.bounds)

            })  // Dispatch queue

}

最佳答案

好吧,有几件事......好吧......以我的拙见我会说选择不当:)

下面是我将如何解决这个问题。

你的基本思路是:

"Have a custom view, that displays stuff according to some information downloaded from the net"

首先,我们应该看看我们需要什么:

  • 您需要一个自定义 View
  • 您需要某种形式的异步下载
  • 你需要一些协调的 Controller
  • 你需要决定整个事情应该如何表现:
    • 是否仅在下载信息时创建 View ?
    • View 是否在一开始就已经存在,同时显示的是什么?
    • 什么触发下载?一些 Controller ?该 View 确实不应该。

现在我们不想将任何异步下载内容混合到 View 中。 View 应该只是愚蠢的并显示它给出的内容。 (我不得不承认我不知道你的 View 实际会显示什么,所以在某些情况下这可能被认为是有效的,但很可能不是)

因此我建议您创建一个单独的类来处理下载和一个单独的类作为您的 View 。

您可以创建一个 NSOperation 子类来执行所有异步操作并由您的 Controller 入队/启动(例如参见 Ray Wenderlich's NSOperation Tutorial)或者您可以这样做使用 GCD 的 Controller 内部的异步内容,以及完成处理程序(在任何一种情况下)告诉 View 重新显示自身。

View 可以在内容未下载时显示一个占位符,并且通过从外部调用一个函数( Controller 将调用它)可以在新内容到达时重新呈现自身。有一件事是肯定的:DrawRect 需要尽可能快!

因此您可能希望在其中有一个 if 语句,并且仅当内容被获取时( View 可以有一个 BoolEnum 来指示此状态) ,您调用 View 的专门绘制方法,否则只需绘制占位符。

并且不要在那里的任何地方使用 dispatch_sync……事实上,根本不要在任何地方使用它。在大多数情况下,您确实希望异步(像往常一样,有异常(exception))。在 drawRect 中的这种特殊情况下,您真的不能像这样使用任何 GCD 函数,因为 drawRect 是在主线程 afaik 上调用的,您不能在主线程之外进行任何绘图。

我希望这能让你开始。否则我可能会在本周晚些时候抽出时间来编写一些代码。

编辑:您可以只使用您拥有的 NSURLDownloadTask,但在 Controller 中。一个单独的 NSOperation 子类在这里可能不是最好的选择,也没有必要。

关于ios - NSURLSession 任务文件下载发生在程序需要使用该文件之后,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29307113/

相关文章:

android - 如何在 iPhone 应用程序和 Android 应用程序中自动刷新 Facebook 访问 token ?

swift - 使用 NSFetchResultsController 时 TableView 不显示任何内容

Xcode Beta 6 - 使用未声明的类型 'CLLocationManagerDelegate'

swift - 单元测试找不到要测试的类

cocoa - 如何将 GCD 对象放入 CF 集合(CFArray、CFDictionary)中?

ios - 快速动态行数

ios - UIView 动画问题 swift 4 Xcode9

ios - 类型 'T' 不符合协议(protocol) 'AnyObject'

ios - 在 Swift 中将其分配给变量之前等待网络请求的结果

ios - 如果我在 dispatch_async block 中有一个 dispatch_sync 调用,然后是第二个 dispatch 调用,那么第二个调用是同步还是异步有关系吗?