Returning data from an async network operation in Swift

Returning data from an async network operation in Swift

Swift is cool

If you’re ever using asynchronous network operations (say GET or POST) and want to return data when calling a method, you’ll quickly understand that it’s not so easy. But you’ll see below how you can do this fairly easily.

Let’s say you have a Class that handles all kinds of network communication. I call mine an “adapter” for lack of a better name. I can call methods on the Class and get data returned from it. You’re never going to be sure when the data returned is available, so you need to set things up with a block. Here is an example method in an adapter Class that I have. I included the Struct so you know how it’s set up. I’m also using AEXML to parse the returned XML to make things easier for me as a developer.

struct SpeakerInformation {
    var deviceID: String
    var name: String
    var type: String
}

func getSpeakerInformation(callback:@escaping (SpeakerInformation) -> () )
{
    var request = URLRequest(url: URL(string: "http://\(ipAddress):\(port)/info")!)
    request.httpMethod = "GET"
    let session = URLSession.shared
    session.dataTask(with: request) { data, response, err in
            
        var options = AEXMLOptions()
        options.parserSettings.shouldProcessNamespaces = false
        options.parserSettings.shouldReportNamespacePrefixes = false
        options.parserSettings.shouldResolveExternalEntities = false
                        
        do {
            let xmlDoc = try AEXMLDocument(xml: data!, options: options)
                
            if let name = xmlDoc.root["name"].value {
                    
                let thisName = name
                let thisDeviceID = xmlDoc.root.attributes["deviceID"]
                let thisType = xmlDoc.root["type"].value!
                let thisInfoPacket = SpeakerInformation(deviceID: thisDeviceID!, name: thisName, type: thisType)
                callback(thisInfoPacket)
            }
        } catch {
            print(error)
        }
        }.resume()
}

See that callback with the typed object? This is how you access the data from this sample GET call. I have the blocked wrapped up in a method.

func whatAreMyDetails() 
{
    // The response object in the block.
    stAdapter.getSpeakerInformation() { (response) in
        if let responseObj = response as SpeakerInformation! {
            DispatchQueue.main.async {
                self.headerLabel.text = responseObj.name
                self.deviceTypeLabel.text = responseObj.type.uppercased()
            }
        }
    }
}

So you can’t set something up which would allow for this kind of syntax:

let foo = stAdpater.getSpeakerInformation()

I hadn’t done a lot of networking calls in quite some time and I stumbled a bit trying to force the direct operation┬ábefore I thought about it some more and did some research. You can return an object, you can return an array of objects, a dictionary, all kinds of stuff. Super handy and the block keeps things nice and tidy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.