2016-02-17 196 views
1

我爲一種新的,以迅速和IOS,我可能有一個同步的問題(不知道),我有一個火力點數據庫給我鑰匙,還有的在Amazon S3上傳內容的網址。我試圖從S3下載圖像,將它們存儲在數組中,然後填充tableview。SWIFT aws S3異步下載?下載圖像和填充的tableview

代碼似乎啓動下載,但它不進步(上進步一個破發點沒有按噸甚至命中)

可能有人給我如何幹淨地填充我的tableview手?我的圖像數組始終是空的,我不知道它是否來自我的s3函數(但不會返回任何錯誤),或者它來自調度事件。

// 
// MainWitness.swift 
// trainning2 
// 
// Created by Yann MASSARD on 2/2/16. 
// Copyright © 2016 Witness. All rights reserved. 
// 

import UIKit 
import Firebase 
import FirebaseUI 


class MainWitness: UIViewController, UITableViewDataSource, UITableViewDelegate { 

    let rootref = Firebase(url: "XXXXXXX/witness/") 
    let refpost = Firebase(url: "XXXXXXX/witness/POSTS") 
    var posts = [getitems]() 
    var Images = [UIImage]() 



    @IBOutlet weak var tableView: UITableView! 

    // S3 download function/called on view did appear, gets the key from firebase 

    func downloadImage(key:String){ 

     var completionHandler: AWSS3TransferUtilityDownloadCompletionHandlerBlock? 

     let S3BucketName: String = "witnesstest/" + rootref.authData.uid 
     let S3DownloadKeyName: String = key 


     let expression = AWSS3TransferUtilityDownloadExpression() 
     expression.downloadProgress = {(task: AWSS3TransferUtilityTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) in 
      dispatch_async(dispatch_get_main_queue(), { 
       let progress = Float(totalBytesSent)/Float(totalBytesExpectedToSend) 
       print("Progress is: \(progress)") 
      }) 
     } 

     completionHandler = { (task, location, data, error) -> Void in 
      dispatch_async(dispatch_get_main_queue(), { 
       if ((error) != nil){ 
        print("Failed with error") 
        print("Error: \(error!)") 
       } 
       else{ 
        //Set your image 
        self.Images.append(UIImage(data: data!)!) 
       } 
      }) 
     } 

     let transferUtility = AWSS3TransferUtility.defaultS3TransferUtility() 

     transferUtility.downloadToURL(nil, bucket: S3BucketName, key: S3DownloadKeyName, expression: expression, completionHander: completionHandler).continueWithBlock { (task) -> AnyObject! in 
      if let error = task.error { 
       print("Error: \(error.localizedDescription)") 
      } 
      if let exception = task.exception { 
       print("Exception: \(exception.description)") 
      } 
      if let _ = task.result { 
       print("Download Starting!")  // shows in console for each firebase post loop 
      } 
      return nil; 
     } 

    } 

    override func viewDidAppear(animated: Bool) { 

     // [1] Call the queryOrderedByChild function to return a reference that queries by the "author" property 
     self.refpost.queryOrderedByChild("author").observeEventType(.Value, withBlock: { snapshot in 

      var newItems = [getitems]() 

      for item in snapshot.children { 

       let postitem = getitems(snapshot: item as! FDataSnapshot) 
       newItems.append(postitem) 

      //  READ IMAGE FROM S3 
       self.downloadImage(postitem.imagekey) 

      } 

      self.posts = newItems 
      self.tableView.reloadData() 
     }) 

    } 


    override func viewDidLoad() { 
     //ref.unauth() 
     super.viewDidLoad() 

     //tableview datasource and delegate 
     tableView.delegate = self 
     tableView.dataSource = self 
    } 



    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 

    override func viewWillAppear(animated: Bool) { 
     // is any user log ? 
     if ((rootref.authData) != nil) { 
      print("user logged") 
     } else { 
      print("user not logged") 
      dispatch_async(dispatch_get_main_queue()){ 

       self.performSegueWithIdentifier("log", sender: self) 

      } 
     } 

    } 

    func numberOfSectionsInTableView(tableView: UITableView) -> Int { 
     return 1 

    } 

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 

     let cell: MainWitnessTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("RIcell") as! MainWitnessTableViewCell 

      // populate the cell 
      let postitem = posts[indexPath.row] 
      cell.postOwner.text = postitem.author 
      cell.postContent.text = postitem.content 
      cell.postDate.text = postitem.createon 

      // cell.cellImage.image = Images[indexPath.row] // returns array index out of range 


     return cell 
    } 

    func tableView(tableView: UITableView, didselectRowAtIndexPath indexPath: NSIndexPath) { 

    } 

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 

     return posts.count 



    } 



} 

回答

0

這個問題已經過去了幾個月,但如果您仍然遇到麻煩,我會給我兩分錢。

在我看來,麻煩在於確定何時刷新表格單元格(假設您從Firebase獲取鍵和從S3獲取數據的所有調用工作正常;如果不是,請考慮編寫一些單元測試或使用遊樂場以確保您可以在視圖控制器的上下文之外正確獲取數據,這將會更快)。

後你會得到你的火力地堡的引用,你在呼喚self.downloadImage(postitem.imagekey),然後self.tableView.reloadData()。由於downloadImage是異步的,因此當您重新加載表格時,您可能沒有任何圖像數據,因此可能是您沒有任何東西的原因。從S3中填充images數組後,必須調用表重新加載。

這是我怎麼會去這樣做:

  1. postsimages陣列都綁在一起;爲什麼不創建一個名爲Posts的結構,其中包含參數postInfo: getitemsimage: UIImage?,其中您可能有也可能沒有該帖子的圖像?那麼你的tableView的數據模型將是var data: [Posts]。每個Post的圖像參數都是零,直到從S3加載。
  2. viewDidLoad:開始查詢到火力地堡的職位和自己的形象鍵。
  3. 在Firebase調用的回調中,如果您收回X個帖子,則可以說您的tableView的數據模型包含X個帖子。將每個帖子追加到您的數組data: [Post]並將.image參數設置爲零,因爲您還沒有任何圖像。一旦所有的帖子都被追加了,你可以重新加載tableView。
  4. tableView:cellForRowAtIndexPath中,如果data[indexPath.row].image的圖像是nil,則可以放入臨時佔位符UIImage以顯示,直到從S3加載實際圖像。如果data[indexPath.row].image不爲零,請設置實際圖像。
  5. 開始下載S3圖像(你仍然可以做到這一點在你的火力地堡通話的回調每個崗位),並更新每次你得到一個像時光倒流的陣列data: [Post]。對於您返回的每張圖片,請僅重新加載該表格單元格。這將再次調用tableView:cellForRowAtIndexPath。由於.image參數將不再爲零,因此您會看到實際圖像會替換佔位符圖像。

這裏是你如何能有效地更新,而不是重新加載整個表只是一個特定的行:

tableView.beginUpdates() 
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.None) 
tableView.endUpdates() 

如果要在陣列中存儲許多大型UIImages你可能有內存問題,可能需要在您將它們滾動到屏幕上而不是一次加載所有圖像之前,先查看保留圖像緩存並加載圖像的幾個索引。