我遇到了一个问题,其中发生了多个异步请求,这些请求从Facebook API和Firebase数据库获取图像和信息。我想执行所有异步请求,然后将从Facebook API / Firebase数据库获取的所有数据存储到一个可以快速加载的完整对象中。我为每个异步请求设置了完成处理程序,我认为这会迫使程序“等待”直到请求完成,然后继续执行程序,但这似乎对我不起作用。以下是我的尝试:
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) } }
我知道我已经在程序中测试了正确设置的完成处理程序。不过,我要的是,只有后两者getAttendees和getAttendeesPictures功能完成,然后,我想所有的商店,我抓住了信息snapshot,getAttendees以及getAttendeesPictures功能,并将它们存储到一个event对象但我的程序似乎仅执行该getAttendees功能,而不执行该getAttendeesPictures功能。以下也是getAttendees和getAttendeesPictures函数:
getAttendees
getAttendeesPictures
snapshot
event
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) } } } }
对于希望在标题中回答问题的用户,请使用dispatch_group此处概述的和GCD:即,将一个组嵌入另一个的通知方法内dispatch_group是有效的。更高级别的另一种方法是NSOperations依赖关系,它还会提供进一步的控制,例如取消操作。
dispatch_group
NSOperations
轮廓 :
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") } } }
该答案的其余部分特定于此代码库。
这里似乎有一些问题:该getAttendees函数接受一个事件子代并返回objectID和Name,它们都是String吗?此方法不应该返回一组参与者吗?如果不是,那么objectID返回的是什么?
objectID
Name
一旦返回了一组与会者,您就可以对他们进行分组处理以获取图片。
在getAttendeesPictures最终返回UIImages从Facebook。最好将它们缓存到磁盘上并传递path ref-保留所有这些获取的图像对内存不利,并且取决于大小和数量,可能很快导致问题。
UIImages
path ref
一些例子:
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 { } }) }
上面的代码只是一个概述,但希望可以为您指明正确的方向。