【问题标题】:reloadData when loop is done循环完成时重新加载数据
【发布时间】:2014-11-15 14:53:37
【问题描述】:

我有一个 loadItem 函数,假设从解析服务器加载项目。这包括一个循环,最后我将数据保存到数组中:

itemArray?.addObject(arrayDic)

保存后,我想重新加载 collectionView 的数据。因此我已将它插入到 dispatch_async 块中,但它似乎仍然在将数据保存到 itemArray 数组之前运行,因为 itemArray.count 为 0,并且我已经在循环内检查了数据是否保存到数组。我究竟做错了什么?

func loadItems() {
    var query = PFQuery(className:"Items")
    query.orderByAscending("createdAt")
    query.findObjectsInBackgroundWithBlock {
        (objects: [AnyObject]!, error: NSError!) -> Void in
        if error == nil {

            for object in objects {

                var imageRelation: PFRelation = object.relationForKey("pictures")


                var query = imageRelation.query()
                query.orderByDescending("createdAt")

                query.findObjectsInBackgroundWithBlock {
                    (imageObjects: [AnyObject]!, error: NSError!) -> Void in
                    if error == nil {

                        var theArray = imageObjects as NSArray

                        var arrayDic = NSMutableDictionary()


                        let imageFile = theArray.objectAtIndex(0).objectForKey("image") as PFFile
                        imageFile.getDataInBackgroundWithBlock {
                            (imageData: NSData!, error: NSError!) -> Void in
                            if !(error != nil) {
                                let image = UIImage(data:imageData)
                                arrayDic.setValue(object.objectForKey("price"), forKey: "price")
                                arrayDic.setValue(image, forKey: "image")
                                itemArray?.addObject(arrayDic)

                            }
                        }


                    }
                }



            }

            dispatch_async(dispatch_get_main_queue()) {

                println(itemArray?.count)
                self.collectionView.reloadData()

            }
        } else {
            // Log details of the failure
            NSLog("Error: %@ %@", error, error.userInfo!)
        }
    }
}

【问题讨论】:

  • 看起来您正在对“query.findObjectsInBackgroundWithBlock”进行两次嵌套调用,而您的reloadData 调用发生在外部findObjectsInBackgroundWithBlock。如果将reloadData 放入内部块会发生什么?
  • 那么它会循环几次?
  • 既然外部findObjectsInBackgroundWithBlock 已经在后台运行,为什么不通过findObjects 重构内部块以同步运行(或作为外部循环的一部分)?然后,找到所有内容后,您可以在外部(也是唯一)块的末尾调用reloadData
  • 你能举个例子吗,不确定我是否完全理解

标签: ios arrays swift parse-platform


【解决方案1】:

我不建议尝试使请求同步(因为这会显着减慢进程,除非您安排它们在某个并发后台队列上同时运行)。相反,我建议使用一种模式,该模式允许您保留异步请求,但会通知您它们已完成。一种这样的模式是调度组,您可以在其中:

  • 创建一个调度组:

    let group = dispatch_group_create() 
    
  • 对于循环的每次迭代,请致电 dispatch_group_enter:

    dispatch_group_enter(group)
    
  • 赢得异步方法的完成块,调用dispatch_group_leave

    dispatch_group_leave(group)
    
  • 指定调度组完成后要执行的操作:

    dispatch_group_notify(group, dispatch_get_main_queue()) {
        println(self.itemArray?.count)
        self.collectionView.reloadData()
    }
    

    当所有对dispatch_group_enter 的调用都被最后的dispatch_group_leave 调用抵消时,将为您调用通知块。

因此,在循环对象时查看代码,它可能看起来像:

let group = dispatch_group_create()

for object in objects {

    dispatch_group_enter(group)

    // do some stuff

    query.findObjectsInBackgroundWithBlock {
        (imageObjects: [PFObject]!, error: NSError!) -> Void in

        if error == nil {

            // do some more stuff

            imageFile.getDataInBackgroundWithBlock {
                (imageData: NSData!, error: NSError!) -> Void in

                if !(error != nil) {
                    // do even some more stuff
                }

                dispatch_group_leave(group)
            }
        } else {
            dispatch_group_leave(group)
        }
    }
}

dispatch_group_notify(group, dispatch_get_main_queue()) {
    println(self.itemArray?.count)
    self.collectionView.reloadData()
}

它们是其他功能等效的模式(例如,自定义并发调度队列,最终 reloadData 使用屏障调度;使这些单独的请求 NSOperation 对象添加到 NSOperationQueue 并创建依赖于的单独完成操作其他操作;等等),但调度组似乎需要对这段代码进行最少的重构。无论如何,希望这说明了基本思想:仅在其他异步请求完成时才触发最终重新加载。

【讨论】:

  • 还可以将 NSOperationQueue 与块操作一起使用
  • 是的,这也有效。但是,如果您正在处理异步任务,则必须创建 NSOperation 子类来包装此异步任务(或以某种方式使它们同步)。我经常更喜欢NSOperation 子类方法(很好地封装了网络请求的细节),但我想让它尽可能简单。而且OP似乎对GCD很熟悉,所以我想把他留在他的舒适区。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-22
  • 2011-01-24
  • 1970-01-01
  • 2014-12-17
相关资源
最近更新 更多