2014-11-09 42 views
0

我的場景:

我異步調用下載器對象函數來嘗試下載文件。爲什麼我的異步調用仍然阻止我與Swift中的UI元素進行交互?

在下載器的功能中,它異步地啓動下載連接。

即便如此,我無法與我的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 
} 

回答

2

兩件事情。

  1. 最重要的是,你仍然可以配置你的配置管理器對主循環運行:

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

    你可能會發現很容易,只需使用NSURLConnection的的類方法 sendAsynchronousRequest:queue:completionHandler:,而不是手動啓動的要求在後臺線程中。

  2. 而且,這是一個糟糕的主意更新從後臺線程的用戶界面元素:

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

    相反,你應該將圖像加載到在後臺一個臨時變量,然後再執行實際分配主線程。

+0

我是否應該在調用此函數時嵌套sendSynchronousRequest:returningResponse:error:在異步塊中?關於它的引用,從來沒有在主線程中調用這個函數 – donkey 2014-11-09 10:19:02

+0

其次,先生,如果不使用NSRunloop.mainRunLoop(),我該如何在獨立或自定義運行循環上調度我的連接? – donkey 2014-11-09 10:51:46

+0

@oasisweng,對不起,我不小心把鏈接指向NSURLConnection上的同步調用,你應該使用 'sendAsynchronousRequest:queue:completionHandler:'來代替。我更新了我的答案。這可以從主線程安全地調用。這就是您如何在後臺線程上安排請求的方式。 – drewag 2014-11-09 18:27:59

相關問題