在加载数据之前完成所有异步请求? [英] Finish all asynchronous requests before loading data?

查看:132
本文介绍了在加载数据之前完成所有异步请求?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到一个问题,我有多个异步请求发生,从Facebook API和我的Firebase数据库抓取图像和信息。我想执行所有的异步请求,然后将我从Facebook API / Firebase数据库抓取的所有数据存储到一个可以快速加载的整个对象中。我为每个异步请求设置完成处理程序,我认为强制程序等待,直到请求完成,然后程序继续,但这似乎不适用于我。以下是我的尝试:

  func setupEvents(completion:(result:Bool,Event:Event) - > Void){
//获取对事件的引用
eventsReference = Firebase(url:< DB Name>)
eventAttendeesRef = Firebase(url:< DB Name>)

//在我们的帖子中读取数据参考
println(事件引用:\(eventsReference))
eventsReference.observeEventType(FEventType.ChildAdded,withBlock:{(snapshot) - > ; Void in

let eventName = snapshot.value [eventName] as?String
let eventLocation = snapshot.value [eventLocation] as?String
let eventCreator = snapshot.value [eventCreator] as?String

var与会者:NSMutableDictionary = [:]
var attendeesImages = [UIImage]()
允许参加者:NSMutableDictionary = [: ]

let group = dispatch_group_create()

//首先获得与会者
dispatch_gr oup_enter(group)
self.getAttendees(snapshot.key as String,completion:{(result,name,objectID) - >空的
if(result == true){
println(完成抓取\(name!)\(objectID!))
attendees.addEntriesFromDictionary(与会者as [NSObject: AnyObject])
}
else {
println(False)
}
dispatch_group_leave(group)
})

//获取参加者照片
dispatch_group_enter(组)
self.getAttendeesPictures(参加者,完成:{(结果,图像) - >
中的虚空如果result == true {
println(完成获取参加者的照片,现在存储到Event对象)
attendeesImages.append(image!)
}
else {
println(false)
}
dispatch_group_leave(group)
})

dispatch_group_notify(group,dispatch_get_main_queue()){
pri ntln(both requests done)
//维护数组快照键
self.eventIDs.append(snapshot.key)

如果快照!= nil {
let event = Event(eventName:eventName,eventLocation:eventLocation,eventPhoto:eventPhoto,fromDate:fromDate,fromTime:fromTime,toDate:toDate,toTime:toTime,与会者:与会者,参加者图像:attendeesImages,attendeesImagesTest:attendeesImagesTest,privacy:privacy,eventCreator :eventCreator,eventCreatorID:eventCreatorID
println(Event:\(event))
completion(result:true,Event:event)
}
}

}){(error) - >空虚
println(error.description)
}
}

我知道我的完成处理程序设置正确,因为我已经在我的程序测试。但是,我想要的是,只有当$ code> getAttendees 和 getAttendeesPictures 函数完成后,我才想存储所有信息我抓住了快照 getAttendees getAttendeesPictures 函数并将它们存储到事件对象中。关于如何实现这一点的任何想法?我试图查看 dispatch_groups ,以帮助我通过这个链接处理这个:,但是我的程序似乎只执行 getAttendees 函数,但不是 getAttendeesPictures 函数。以下也是 getAttendees getAttendeesPictures 函数:

  func getAttendees(child:String,completion:(result:Bool,name:String?objectID:String?) - > Void){
//获取特定事件的参加者事件
var attendeesReference = self.eventAttendeesRef.childByAppendingPath(child)
println(加载事件参与者)
//获取所有活动参与者
attendeesReference.observeEventType(FEventType.ChildAdded, withBlock:{(snapshot) - > Void in
let name = snapshot.value.objectForKey(name)as?String
let objectID = snapshot.value.objectForKey(objectID)as? String
println(Name:\(name)Object ID:\(objectID))
completion(result:true,name:name,objectID:objectID)
}){ (错误) - >空的
println(error.description)
}

func getAttendeesPictures(与会者:NSMutableDictionary,完成:(结果:Bool,image:UIImage?) - > Void){
println(Attendees Count:\(attendees.count))
for(key,value)在参加者中{
let url = NSURL(string:https:// graph。
println(URL:\(url))
let urlRequest = NSURLRequest(URL:url!)
//显示图像的异步请求
NSURLConnection.sendAsynchronousRequest(urlRequest,queue:NSOperationQueue.mainQueue()){(response:NSURLResponse !, data:NSData !, error:NSError!) - >
如果错误!= nil {
println(Error:\(error))
}
//显示图像
let image = UIImage (data:data)
if(image!= nil){
completion(result:true,image:image)
}
}
}


对于要求标题问题回答的用户,请使用的 dispatch_group 和GCD概述:即将另一个 dispatch_group 的通知方法嵌入一个组是有效的。另一种在较高级别上的方式是 NSOperations 和依赖关系,这也将进一步控制,如取消操作。



大纲

  func doStuffonObjectsProcessAndComplete(arrayOfObjectsToProcess:Array) - > Void){

let firstGroup = dispatch_group_create()

在arrayOfObjectsToProcess中的对象{

dispatch_group_enter(firstGroup)

doStuffToObject(object,completion:{(success)in
if(success){
//做东西成功
}
else {
//做东西失败
}
//不管怎么样,我们让GCD知道我们完成了这一点工作
dispatch_group_leave(firstGroup)
})
}

//所有进入组的代码块都离开
dispatch_group_notify(firstGroup,dispatch_get_main_queue()){

let processGroup = dispatch_group_create()

对象在arrayOfObjectsToProcess {

dispatch_group_enter(processGroup)

processObject(object,completion:{(success)in
如果(成功){
//处理东西成功
}
else {
//处理东西失败
}
//不管我们离开小组让GCD知道我们完成了这项工作
dispatch_group_leave(processGroup)
})
}

dispatch_group_notify(processGroup,dispatch_get_main_queue()){
print(全部完成和处理,所以现在加载数据)
}
}
}

此答案的其余部分是该代码库的特定。



这里似乎有一些问题:
getAttendees 函数需要一个事件child,并返回一个 objectID Name 哪些都是字符串?这个方法不应该返回一个与会者的数组吗?如果没有,那么返回的 objectID 是什么?



一旦返回参加者数组,那么你可以在一组中处理它们以获取图片。



getAttendeesPictures 最终返回 UIImages来自Facebook的最好将它们缓存到磁盘上,并通过 path ref - 保留所有这些获取的图像不利于内存,并且根据大小和数量,可能会很快导致



一些示例:

  func getAttendees(child:String,completion:(result:Bool,attendees:Array?) - > Void){

let newArrayOfAttendees = []()

/ /获取特定事件的活动参与者

//处理参加者和打包到数组(或词典)

//完成
完成(true,与会者:newArrayOfAttendees )
}

func getAttendeesPictures(与会者:数组,完成:(结果:Bool,与会者:数组) - > Void){

println(计数:\(attendees.count))

let picturesGroup = dispatch_group_create()

参加者的参加者{

//每个参加者进入组
dis patch_group_enter(picturesGroup)

let key = attendee.objectID

let url = NSURL(string:https://graph.facebook.com/\(key)/图片?type = large)

let urlRequest = NSURLRequest(URL:url!)

//显示图像的异步请求
NSURLConnection.sendAsynchronousRequest(urlRequest, queue:NSOperationQueue.mainQueue()){(response:NSURLResponse !, data:NSData !, error:NSError!) - >
如果错误!= nil {
println(Error:\(error))
}

//显示图像
let image = UIImage(data:data)
if(image!= nil){
attendee.image = image
}

dispatch_group_leave(picturesGroup)



dispatch_group_notify(图片集,dispatch_get_main_queue()){
完成(真,参加者:与会者)
}
}

func setupEvents(completion:(result:Bool,Event:Event) - > Void){

//获取事件信息,然后为每个事件...

getAttendees(child:snapshot.key,completion:{(result,attendeesReturned)in
if result {
self.getAttendeesPictures(Participees:attendeesReturned,completion:{(result,attendees)in

//用完成的数组和与会者
做一些事情

}
}
其他{

}
})

}

上面的代码只是一个大纲,但希望能指向正确的方向。


I have run into an issue where I have multiple asynchronous requests occuring which grab images and information from the Facebook API and my Firebase database. I want to perform all my asynchronous requests, then store all that data that I grabbed from the Facebook API/Firebase database into one entire object which I can quickly load. I have set up completion handlers for every asynchronous request which I thought forces the program to "wait" until the request is complete and then have the program continue, but that doesn't seem to work for me. Below is my attempt:

func setupEvents(completion: (result: Bool, Event: Event) -> Void){
    // Get a reference to Events
    eventsReference = Firebase(url:"<DB Name>")
    eventAttendeesRef = Firebase(url:"<DB Name>")

    //Read the data at our posts reference
    println("Event References: \(eventsReference)")
    eventsReference.observeEventType(FEventType.ChildAdded, withBlock: { (snapshot) -> Void in

        let eventName = snapshot.value["eventName"] as? String
        let eventLocation = snapshot.value["eventLocation"] as? String
        let eventCreator = snapshot.value["eventCreator"] as? String

        var attendees: NSMutableDictionary = [:]
        var attendeesImages = [UIImage]()
        let attendee: NSMutableDictionary = [:]

        let group = dispatch_group_create()

        //Get attendees first
        dispatch_group_enter(group)
        self.getAttendees(snapshot.key as String, completion:{ (result, name, objectID) -> Void in
            if(result == true){
                println("Finished grabbing \(name!) \(objectID!)")
                attendees.addEntriesFromDictionary(attendee as [NSObject : AnyObject])
            }
            else {
                println("False")
            }
            dispatch_group_leave(group)
        })

        //Get attendees photos
        dispatch_group_enter(group)
        self.getAttendeesPictures(attendee, completion: { (result, image) -> Void in
            if result == true {
                println("Finished getting attendee photos. Now to store into Event object.")
                attendeesImages.append(image!)
            }
            else{
                println("false")
            }
            dispatch_group_leave(group)
        })

        dispatch_group_notify(group, dispatch_get_main_queue()) {
            println("both requests done")
            //Maintain array snapshot keys
            self.eventIDs.append(snapshot.key)

            if snapshot != nil {
                let event = Event(eventName: eventName, eventLocation:eventLocation, eventPhoto:eventPhoto, fromDate:fromDate, fromTime:fromTime, toDate:toDate, toTime:toTime, attendees: attendees, attendeesImages:attendeesImages, attendeesImagesTest: attendeesImagesTest, privacy:privacy, eventCreator: eventCreator, eventCreatorID: eventCreatorID)
                println("Event: \(event)")
                completion(result: true, Event: event)
            }
        }

        }) { (error) -> Void in
            println(error.description)
    }
}

I know I have my completion handlers set correctly as I have tested in my program. However, what I want is that only after both the getAttendees and getAttendeesPictures function completes, I then want to store all the information I grabbed the snapshot, getAttendees, and getAttendeesPictures function and store them into an event object. Any ideas on how to accomplish this? I've tried to look into dispatch_groups to help me handle this via this link: Checking for multiple asynchronous responses from Alamofire and Swift but my program seems to only execute the getAttendees function but not the getAttendeesPictures function. Below are also the getAttendees and getAttendeesPictures functions:

func getAttendees(child: String, completion: (result: Bool, name: String?, objectID: String?) -> Void){
    //Get event attendees of particular event
    var attendeesReference = self.eventAttendeesRef.childByAppendingPath(child)
    println("Loading event attendees")
    //Get all event attendees
    attendeesReference.observeEventType(FEventType.ChildAdded, withBlock: { (snapshot) -> Void in
        let name = snapshot.value.objectForKey("name") as? String
        let objectID = snapshot.value.objectForKey("objectID") as? String
        println("Name: \(name) Object ID: \(objectID)")
        completion(result: true, name: name, objectID: objectID)
        }) { (error) -> Void in
            println(error.description)
    }

 func getAttendeesPictures(attendees: NSMutableDictionary, completion: (result: Bool, image: UIImage?)-> Void){
    println("Attendees Count: \(attendees.count)")
    for (key, value) in attendees{
        let url = NSURL(string: "https://graph.facebook.com/\(key)/picture?type=large")
        println("URL: \(url)")
        let urlRequest = NSURLRequest(URL: url!)
        //Asynchronous request to display image
        NSURLConnection.sendAsynchronousRequest(urlRequest, queue: NSOperationQueue.mainQueue()) { (response:NSURLResponse!, data:NSData!, error:NSError!) -> Void in
            if error != nil{
                println("Error: \(error)")
            }
            // Display the image
            let image = UIImage(data: data)
            if(image != nil){
                completion(result: true, image: image)
            }
        }
    }
}

解决方案

For users seeking answer to question in title then use of dispatch_group and GCD outlined here: i.e embedding one group inside the notification method of another dispatch_group is valid. Another way to go at a higher level would be NSOperations and dependencies which would also give further control such as canceling operations.

Outline:

func doStuffonObjectsProcessAndComplete(arrayOfObjectsToProcess: Array) -> Void){

    let firstGroup = dispatch_group_create()

    for object in arrayOfObjectsToProcess {

        dispatch_group_enter(firstGroup)

        doStuffToObject(object, completion:{ (success) in
            if(success){
                // doing stuff success
            }
            else {
                // doing stuff fail
            }
            // regardless, we leave the group letting GCD know we finished this bit of work
            dispatch_group_leave(firstGroup)
        })
    }

    // called once all code blocks entered into group have left
    dispatch_group_notify(firstGroup, dispatch_get_main_queue()) {

        let processGroup = dispatch_group_create()

        for object in arrayOfObjectsToProcess {

            dispatch_group_enter(processGroup)

            processObject(object, completion:{ (success) in
                if(success){
                    // processing stuff success
                }
                else {
                    // processing stuff fail
                }
                // regardless, we leave the group letting GCD know we finished this bit of work
                dispatch_group_leave(processGroup)
            })
        }

        dispatch_group_notify(processGroup, dispatch_get_main_queue()) {
            print("All Done and Processed, so load data now")
        }
    }
}

The remainder of this answer is specific to this codebase.

There seem to be a few problems here: The getAttendees function takes an event child and returns an objectID and Name which are both Strings? Shouldn't this method return an array of attendees? If not, then what is the objectID that is returned?

Once an array of attendees is returned, then you can process them in a group to get the pictures.

The getAttendeesPictures eventually returns UIImages from Facebook. It's probably best to cache these out to the disk and pass path ref - keeping all these fetched images around is bad for memory, and depending on size and number, may quickly lead to problems.

Some examples:

func getAttendees(child: String, completion: (result: Bool, attendees: Array?) -> Void){

    let newArrayOfAttendees = []()

    // Get event attendees of particular event

    // process attendees and package into an Array (or Dictionary)

    // completion
    completion(true, attendees: newArrayOfAttendees)
}

func getAttendeesPictures(attendees: Array, completion: (result: Bool, attendees: Array)-> Void){

    println("Attendees Count: \(attendees.count)")

    let picturesGroup = dispatch_group_create()

    for attendee in attendees{

       // for each attendee enter group
       dispatch_group_enter(picturesGroup)

       let key = attendee.objectID

       let url = NSURL(string: "https://graph.facebook.com/\(key)/picture?type=large")

        let urlRequest = NSURLRequest(URL: url!)

        //Asynchronous request to display image
        NSURLConnection.sendAsynchronousRequest(urlRequest, queue: NSOperationQueue.mainQueue()) { (response:NSURLResponse!, data:NSData!, error:NSError!) -> Void in
            if error != nil{
                println("Error: \(error)")
            }

            // Display the image
            let image = UIImage(data: data)
            if(image != nil){
               attendee.image = image
            }

            dispatch_group_leave(picturesGroup)
        }
    }

    dispatch_group_notify(picturesGroup, dispatch_get_main_queue()) {
         completion(true, attendees: attendees)
    }
}

func setupEvents(completion: (result: Bool, Event: Event) -> Void){

    // get event info and then for each event...

    getAttendees(child:snapshot.key, completion: { (result, attendeesReturned) in
        if result {
            self.getAttendeesPictures(attendees: attendeesReturned,         completion: { (result, attendees) in

              // do something with completed array and attendees


            }
        }
        else {

        }
    })

}

The above code is just an outline, but hopefully points you in the right direction.

这篇关于在加载数据之前完成所有异步请求?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆