2017-02-28 21 views
0

我試圖做一個應用程序,使用Web服務從目錄獲取一些數據,但我也需要將數據保存到設備中,包括圖像,這樣做我正在使用AlamofireAlamofireImage消費Web服務的框架。我使用Realm框架和圖像將生成的對象保存在數據庫中,並將UIImage保存到文件中。如何使用Swift在後臺線程中保存文件?

基本上,ViewController有一個顯示de數據的tableView,但是由於圖像寫入文件,它看起來很遲鈍。

這是我寫的函數:

func saveImage(_ image: UIImage) { 
    if let data = UIImagePNGRepresentation(image) { 
     let name = "images/person_directory_\(id).png" 
     let docsDir = getDocumentsDirectory() 
     let filename = docsDir.appendingPathComponent(name) 
     let fm = FileManager.default 

     if !fm.fileExists(atPath: docsDir.appendingPathComponent("images").path) { 
      do { 
       try fm.createDirectory(at: docsDir.appendingPathComponent("images"), withIntermediateDirectories: true, attributes: nil) 
       try data.write(to: filename) 
       try! realm?.write { 
        self.imageLocal = name 
       } 
      } 
      catch { 
       print(error) 
      } 
     } 
     else { 
      do { 
       try data.write(to: filename, options: .atomic) 
       try! realm?.write { 
        self.imageLocal = name 
       } 
      } 
      catch { 
       print(error) 
      } 

     } 
    } 
} 

我調用此函數時Alamofire下載圖像

if person.imageLocal != nil, let image = person.loadLocalImage() { 
     print("Load form disk: \(person.imageLocal)") 
     cell.imgProfile.image = image 
    } 
    else if !(person.image?.isEmpty)! { 
     Alamofire.request(person.image!).responseImage(completionHandler: { (response) in 
      if response.result.isSuccess { 
       if let image = response.result.value { 
        person.saveImage(image) 
        cell.imgProfile.image = image 
        print("Downloaded: \(person.imageLocal)") 
       } 
      } 
     }) 
    } 

但滾動時的tableView看起來laggy,我試圖讓寫作操作轉換爲不同的線程,以便在不影響應用程序性能的情況下使用DispatchQeue

DispatchQueue.global(qos: .background).async { 
        do { 
         try data.write(to: filename) 
        } 
        catch { 
         print(error) 
        } 
       } 

但即便如此,應用程序仍然滯後。

UPDATE:

我tryed這是羅布建議:

func saveImage(_ image: UIImage) { 
    if let data = UIImagePNGRepresentation(image) { 
     let name = "images/person_directory_\(id).png" 
     do { 
      try realm?.write { 
       self.imageLocal = name 
      } 
     } 
     catch { 
      print("Realm error") 
     } 
     DispatchQueue.global().async { 
      let docsDir = self.getDocumentsDirectory() 
      let filename = docsDir.appendingPathComponent(name) 
      let fm = FileManager.default 

      if !fm.fileExists(atPath: docsDir.appendingPathComponent("images").path) { 
       do { 
        try fm.createDirectory(at: docsDir.appendingPathComponent("images"), withIntermediateDirectories: true, attributes: nil) 
       } 
       catch { 
        print(error) 
       } 
      } 
      do { 
       try data.write(to: filename) 
      } 
      catch { 
       print(error) 
      } 
     } 
    } 
} 

我不能分派境界becase的寫作境界並不能支持多線程。 它仍然在滾動laggy,但不如第一次。

+0

您可能希望將標題調整爲該問題,因爲您在背景中編寫了正確的代碼。 – Mozahler

+1

「laggy」是什麼意思?您的主線程是否滯後,即桌面滾動有點滑稽,還是僅僅是圖像沒有像您期望的那樣顯示在桌面上?另外我看到的是,你保持對AlamoFire中表格單元格的引用。request()關閉 - 如果您有很多單元格並且用戶滾動,那麼該單元格可能會被重新使用。也許保持單元格的索引,並重新加載單元格,一旦你有圖像。 – joeybladb

+0

爲了擴大joeybladb的問題,圖像不會立即出現的問題(您可以考慮通過指定['prefetchDataSource']來解決這個問題)(https://developer.apple.com/reference/uikit/uitableview/1771763 -prefetchdatasource))或滾動不平滑(即它的口吃)? – Rob

回答

0

所以正確答案爲@Rob給了它是

DispatchQueue.global().async { 
     do { 
     try data.write(to: filename) 
     } 
     catch { 
     print(error) 
     } 
    } 

但同樣重要的是永遠不要從一個異步調用(再次信用@Rob)使用一個UITableViewCell的參考。例如,從代碼的異步部分設置單元格值。

   cell.imgProfile.image = image 

UITableViewCells被重新使用,因此您不知道原始單元格仍然在相同索引處使用。對於測試,如果您看到圖像出現在錯誤的單元格中,那麼您的列表會非常快速地滾動以便您的圖像加載,這是重用問題。

因此,從一個異步回調你需要弄清楚新圖像的單元格索引是否可見,去獲取該索引的當前單元格以設置它的圖像。如果索引不可見,則存儲/緩存圖像,直到其索引滾動到視圖中。此時它的單元格將使用UITableView.cellForRowAtIndexPath創建,並且您可以在那裏設置圖像。

相關問題