Finish all asynchronous requests before loading data?

前端 未结 6 912
被撕碎了的回忆
被撕碎了的回忆 2020-11-27 18:57

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 per

6条回答
  •  长情又很酷
    2020-11-27 19:47

    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.

提交回复
热议问题