2015-08-16 25 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 

     } 
    }