在加载数据之前完成所有异步请求? [英] Finish all asynchronous requests before loading data?
问题描述
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屋!