循环完成后重新加载数据

时间:2014-11-15 14:53:38

标签: ios arrays swift parse-platform

我有一个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!)
        }
    }
}

1 个答案:

答案 0 :(得分:0)

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

  • 创建一个调度组:

    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并创建单独的完成操作依赖于那些其他操作;等等),但调度组似乎需要对此​​代码进行最少的重构。无论如何,希望这说明了基本思想:只有在完成其他异步请求时才会触发最终重新加载。