2015-08-16 54 views
2

我一直在努力讓我的tableview正確加載.count。我必須找到一種方法來告訴tableview,僅在我的圖像和文章數組完全填充後才加載。UITableView:推遲重新加載,直到所有數據已在後臺下載

否則我將保持在

cell.cellImage?.image = imagesArray[indexPath.row] 

cellForRowAtIndexPath 

輸出得到一個

fatal error: Array index out of range 

NUMBER OF POSTS->0 
    NUMBER OF IMAGES->0 
    NUMBER OF POSTS->0 
    NUMBER OF IMAGES->0 
    NUMBER OF POSTS->0 
    NUMBER OF IMAGES->0 
    POSTSARRAY COUNT->1 
    POSTSARRAY COUNT->2 
    POSTSARRAY COUNT->3 
    POSTSARRAY COUNT->4 

    NUMBER OF POSTS->4 
    NUMBER OF IMAGES->0 

    IMAGESARRAY COUNT->1 
    IMAGESARRAY COUNT->2 
    IMAGESARRAY COUNT->3 
    IMAGESARRAY COUNT->4 

    NUMBER OF POSTS->4 
    NUMBER OF IMAGES->4 

代碼

override func viewDidLoad() { 
     super.viewDidLoad() 

//  myTableView.estimatedRowHeight = 312.0 
//  myTableView.rowHeight = UITableViewAutomaticDimension 

     var query = PFQuery(className: "Post") 
     query.whereKey("hobbieTag", equalTo:"\(selectedHobbie)") 
     query.orderByAscending("description") 
     query.findObjectsInBackgroundWithBlock 
      { 
       (objects: [AnyObject]?, error: NSError?) -> Void in 

       if error == nil 
       { 
        //    println("HOBBIES.COUNT->\(hobbies?.count)") 
        for post in objects! 
        { 
         //GET POST TITLE 
         self.posts.append(post["postText"] as! String) 
         println("POSTSARRAY COUNT->\(self.posts.count)") 

         //TEST IMAGE 
         //var appendImage = UIImage(named: "logoPDF") 
         //self.imagesArray.append(appendImage!) 

         //GET IMAGE FILE 
         let postImageFile = post["postImage"] as? PFFile 
         postImageFile?.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in 

          var image = UIImage(data: imageData!) 
          self.imagesArray.append(image!) 
          println("IMAGESARRAY COUNT->\(self.imagesArray.count)") 

          }, progressBlock: { (progress: Int32) -> Void in 
//        println("PROGRESS->\(progress)") 
         }) 
        } 
        self.myTableView.reloadData() 
       } 
       else 
       { 
        println(error?.localizedDescription) 
        println(error?.code) 
       } 
//    self.myTableView.reloadData() 
     }//END query 
    } 

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


    override func viewDidAppear(animated: Bool) { 
     myTableView.reloadData() 
    } 

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     println("NUMBER OF POSTS->\(posts.count)") 
     println("NUMBER OF IMAGES->\(imagesArray.count)") 
     return posts.count 
    } 

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
     let cellIdentifier = "Cell" 
     let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! HobbieFeedTableViewCell 

     cell.cellTitle.text = posts[indexPath.row] 
     cell.cellSubtitle.text = posts[indexPath.row] 


     //  cell.cellImage.image = UIImage(named: "logoPDF") 
     //cell.cellImage?.image = imagesArray[indexPath.row] 

     return cell 
    } 

更新代碼

 var query = PFQuery(className: "HobbieFeed") 
     query.whereKey("hobbieTag", equalTo:"\(selectedHobbie)") 
     query.orderByAscending("description") 
     query.findObjectsInBackgroundWithBlock 
      { 
       (objects: [AnyObject]?, error: NSError?) -> Void in 

       if error == nil 
       { 
        let semaphore = dispatch_semaphore_create(0) 

        //    println("HOBBIES.COUNT->\(hobbies?.count)") 
        for post in objects! 
        { 
         //GET POST TITLE 
         self.posts.append(post["postText"] as! String) 
         println("POSTSARRAY COUNT->\(self.posts.count)") 

         //TEST IMAGE 
         //var appendImage = UIImage(named: "logoPDF") 
         //self.imagesArray.append(appendImage!) 

         //GET IMAGE FILE 
         let postImageFile = post["postImage"] as? PFFile 
         postImageFile?.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in 

          var image = UIImage(data: imageData!) 
          self.imagesArray.append(image!) 
          println("IMAGESARRAY COUNT->\(self.imagesArray.count)") 

          dispatch_semaphore_signal(semaphore) 

          }, progressBlock: { (progress: Int32) -> Void in 
           println("PROGRESS->\(progress)") 
         }) 


        } 

        // Wait for all image loading tasks to complete 
        for post in objects! { 
         dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) 
         println("SHAPHORE POSTS COUNT->\(self.posts.count)") 
         println("SEMAPHORE IMAGES COUNT->\(self.imagesArray.count)") 
        } 

        self.myTableView.reloadData() 
       } 

     }//END query 

回答

2

你在一個循環的背景踢的圖像加載和循環後立即打電話reloadData。但是,此時後臺任務還沒有完成。

for post in objects! { 
    ... 
    // This starts a background operation 
    postImageFile?.getDataInBackgroundWithBlock(...) 
    ... 
} 
// The background tasks are not necessarily completed at this point 
self.myTableView.reloadData() 

要等到所有後臺任務完成,您可以使用信號量。這是一個基本的例子。

// Create a new semaphore with a value of 0 
let semaphore = dispatch_semaphore_create(0) 

// Kick off a bunch of background tasks 
for i in 0...10 { 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 
     sleep(1) // Do some work or sleep 

     // Signal the semaphore when the task is done. This increments 
     // the semaphore. 
     dispatch_semaphore_signal(semaphore) 
    } 
} 

// Wait until all background tasks are done 
for i in 0...10 { 
    // This waits until the semaphore has a positive value 
    // and then decrements it 
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) 
} 

// This is only executed after all background tasks are done 
println("all tasks are done") 

請注意,可以通過使用分派組簡化該示例。然而,在你的情況下,這不是一個選項,因爲你使用完成處理函數調用函數,而不是直接在隊列上執行塊。

將上面的方法應用到您的代碼將如下所示。

let semaphore = dispatch_semaphore_create(0) // Create a semaphore (value: 0) 

for post in objects! { 
    ... 
    postImageFile?.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in 
     ... // Do your work 

     // Increment the semaphore when the image loading is completed 
     dispatch_semaphore_signal(semaphore) 
    }, progressBlock: { 
     ... 
    }) 
    ... 
} 

// Wait for all image loading tasks to complete 
for post in objects! { 
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) 
} 

// This is only called after all images have loaded 
self.myTableView.reloadData() 
+0

感謝您的幫助。我將更改應用於代碼。但不幸的是它沒有奏效。現在它讀取** FIRST **'self.posts.append(post [「postText」] as!String)',然後在加載第一個圖像之前停止。我放了它一段時間,以防止它加載很長時間,但只是沒有更進一步。 – GuiSoySauce

+0

@GuiSoySauce你確定在第一個循環以外的第二個'對象'循環中調用'dispatch_semaphore_wait'嗎? – hennes

+0

@GuiSoySauce嗯,對不起,我沒有看到任何理由爲什麼你的更新的代碼將無法正常工作。儘管您還應該確保按照其他答案中的建議在主隊列上執行表視圖更新。 – hennes

1

嗨據我可以看到你做的是正確的事情,在後臺異步加載數據。我認爲它失敗的地方在於重新加載表的異步塊中。試試這裏的代碼:

dispatch_async(dispatch_get_main_queue()){self.myTableView.reloadData()} 

該塊實際上運行在af不同的線程,因此它不會與其他代碼同步。如果你正在使用測試,這也是一個問題,以正確測試異步塊。在這裏你可以使用waitForExpectationsWithTimeout(秒)來測試你的代碼是否正確

0

終於解決了這個問題。可能對其他用戶有幫助,所以會在這裏發佈答案。

托克一種不同的方法,我相信更簡單。

該查詢發生在視圖確實加載,但在該階段沒有單獨的圖像或內容數組。單元格獲取整個查詢對象數組,然後檢索每行所需的內容。也更容易檢測是否有圖像。

全球陣列:

var timelineData = NSMutableArray() 

查看所做負荷查詢:

var query = PFQuery(className: "Feed") 
    query.whereKey("Tag", equalTo:"\(selected)") 
    query.orderByAscending("description") 
    query.findObjectsInBackgroundWithBlock 
     { 
      (objects: [AnyObject]?, error: NSError?) -> Void in 

      if error == nil 
      { 
       for object in objects! 
       { 
        self.timelineData.addObject(object) 
       } 
       self.myTableView.reloadData() 
      } 
    }//END query 

的tableview cellforrow

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

     //Cell identifiers 
     let standardCellIdentifier = "StandardCell" 
     let imageCellIdentifier = "ImageCell" 

     //get object, text and votes 
     let object = self.timelineData.objectAtIndex(indexPath.row) as! PFObject 
     var myText = object.objectForKey("postText") as? String 
     var hasImage = object.objectForKey("hasImage") as? Bool 
     var myVotes = object.objectForKey("votes") as! Int 
     let imageFromParse = object.objectForKey("postImage") as? PFFile 

     //if image 
     if hasImage == true 
     { 
      let imageCell = tableView.dequeueReusableCellWithIdentifier(imageCellIdentifier, forIndexPath: indexPath) as! FeedImageTVCell 

      //set image for cell 
      imageFromParse!.getDataInBackgroundWithBlock({ (imageData:NSData?, error:NSError?) -> Void in 
       if error == nil { 

        if let myImageData = imageData { 
         let image = UIImage(data:myImageData) 
         imageCell.cellImage!.image = image 
        } 
       } 
       }, progressBlock: { (percent: Int32) -> Void in 
      }) 
      imageCell.cellVotes.text = "Votes - \(myVotes)" 
      imageCell.cellText.text = myText 
      return imageCell 
     } 
     //if no image 
     else 
     { 
      let standardCell = tableView.dequeueReusableCellWithIdentifier(standardCellIdentifier, forIndexPath: indexPath) as! FeedStandardTVCell 
      standardCell.cellVotes.text = "Votes - \(myVotes)" 
      standardCell.cellText.text = myText 
      return standardCell 

     } 
    }