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.