当前位置: 首页 > 面试题库 >

在加载数据之前完成所有异步请求?

胡昊
2023-03-14
问题内容

我遇到了一个问题,其中发生了多个异步请求,这些请求从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)
    }
}

我知道我已经在程序中测试了正确设置的完成处理程序。不过,我要的是,只有后两者getAttendeesgetAttendeesPictures功能完成,然后,我想所有的商店,我抓住了信息snapshotgetAttendees以及getAttendeesPictures功能,并将它们存储到一个event对象但我的程序似乎仅执行getAttendees功能,而不执行该getAttendeesPictures功能。以下也是getAttendeesgetAttendeesPictures函数:

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依赖关系,它还会提供进一步的控制,例如取消操作。

轮廓

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函数接受一个事件子代并返回objectIDName,它们都是String吗?此方法不应该返回一组参与者吗?如果不是,那么objectID返回的是什么?

一旦返回了一组与会者,您就可以对他们进行分组处理以获取图片。

getAttendeesPictures最终返回UIImages从Facebook。最好将它们缓存到磁盘上并传递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 {

        }
    })

}

上面的代码只是一个概述,但希望可以为您指明正确的方向。



 类似资料:
  • 主要内容:echarts_test_data.json 数据:,实例,实例,实例ECharts 通常数据设置在 setOption 中,如果我们需要异步加载数据,可以配合 jQuery等工具,在异步获取数据后通过 setOption 填入数据和配置项就行。 ECharts 通常数据设置在 setOption 中,如果我们需要异步加载数据,可以配合 jQuery等工具,在异步获取数据后通过 setOption 填入数据和配置项就行。 json 数据: echarts_test_

  • 我需要把所有的结果推入一个数组,使异步超文本传输协议调用,但我需要等到所有的调用都完成。 这里只有等待这个选项吗?我害怕使用它,因为等待每个请求会减慢整个过程。

  • 问题内容: 我正在使用Angular构建Web应用程序,并且试图找到一种方法来等待所有元素都经过评估并且包括完成加载。例如,菜单是一个已加载的视图,每个页面的主要内容也是如此,因此至少有两个s被评估并加载。最重要的是菜单包含嵌套s,它们构成了我的菜单。在所有这些包含项以及其中的所有角度函数均已加载并且DOM已准备就绪之后,我需要一种启动脚本的方法。 Angular完成页面设置后,是否会触发任何事件

  • 我正在使用Firebase实时数据库为我的Android应用程序存储和检索数据。在我的活动中,我使用从Firebase检索所有数据(例如:用户数据列表)。 我想显示一个进度条,只要数据没有完全从数据库中检索出来。如何检查是否全部检索到了所有数据,以便在加载数据后关闭进度条?

  • 我使用相同的输入Json在REST API上提交多个POST提交。这意味着多用户(例如:10000)使用相同的Json提交相同的POST来测量POST请求的性能,但是我需要使用GET方法捕获每次提交的完成结果,并且仍然测量GET的性能。这是一个如下的异步过程。 提交后 因此,我需要创建一个jmeter测试计划,该计划可以处理多用户提交的异步POST,并等待它们被处理,最后捕获每次提交的完成情况。我

  • 如何在包含回收器视图的活动开始时显示Progressbar,一旦回收器视图从firebase数据库加载数据,应该隐藏该视图? 在onCreate方法中,我显示了我的ProgressBar,但我不知道什么时候应该隐藏它。 你们能给我点主意吗?谢谢