0

我的场景:

我异步调用下载器对象函数来尝试下载文件。

在下载器的函数中,它异步启动下载连接。

即便如此,我也无法与我的 UI 元素进行交互。

例如,在下载过程中我无法编辑我的文本字段。

我希望能够在下载时与我的 UI 元素进行交互。

我错过了哪里?我应该怎么办?我真的很感谢你的帮助!


ViewController 的异步下载片段

//relevant UI elements I am referring to
@IBOutlet var renderButton: UIButton!
@IBOutlet var urlField: UITextField!

func handleOpenURL(url: NSURL){
    var downloader: aDownloader = aDownloader(url: url)

    //I try to put download to background thread
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {() -> Void in

        //This function initiates a connection call in an attempt to download the file
        downloader.executeConnection({ 
            (dataURL:NSURL!,error:NSError!) -> Void in  

                 dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    self.imageView.image = UIImage(data:NSData(contentsOfURL: url)!)
                 })

                 //rest are nonsense
            }, progress: { (percentage:Double) -> Void in
                 //nonsense
            }
        )

     })
}

aDownloader.swift 的相关代码片段

class aDownloader: NSObject, allOtherProtocols {
    unowned var url: NSURL

    //this block reports the progress as a % number 
    var progressBlock : ((Double)->Void)?

    //this block will return either the destinationFileURL after download finishes,
    //or return error of any sort
    var dataBlock: ((NSURL!,NSError!)->Void)?

    init(url: NSURL) {
        self.url = url
    }

    func executeConnection(received:(NSURL!,NSError!)->Void, progress:(Double)->Void){
        var request : NSURLRequest = NSURLRequest(URL: self.url, 
                                                  cachePolicy: .ReloadIgnoringLocalCacheData,
                                                  timeoutInterval: 60.0)

        //I attempt to async-ly download the file here
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), { () -> Void in
            var connectionManager : NSURLConnection? = NSURLConnection(request:request, 
                                                                       delegate: self, 
                                                                       startImmediately: false)
            connectionManager?.scheduleInRunLoop(NSRunLoop.mainRunLoop(), 
                                                 forMode: NSRunLoopCommonModes)
            connectionManager?.start()
        })

        self.dataBlock = received
        self.progressBlock = progress
    }

    //nonsense
}
4

1 回答 1

2

两件事情。

  1. 最重要的是,您仍在将配置管理器配置为在主循环上运行:

    connectionManager?.scheduleInRunLoop(NSRunLoop.mainRunLoop(), 
                                             forMode: NSRunLoopCommonModes)
    

    你可能会发现只使用 NSURLConnection 的类方法 sendAsynchronousRequest:queue:completionHandler:而不是在后台线程中手动启动请求更容易。

  2. 此外,从后台线程更新 UI 元素也是一个坏主意:

    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        self.imageView.image = UIImage(data:NSData(contentsOfURL: url)!)
    })
    

    相反,您应该将图像加载到后台的临时变量中,然后在主线程上执行实际分配。

于 2014-11-09T03:42:43.067 回答