0

I'm trying to find a way to handle asynchronous network requests in Swift. My plan is to isolate these calls in their own class, so I need a way to handle callbacks. In Android, I'm doing something like the following using an Interface:

apiService.fetch(data, new Callback() {
    @Override
    public void onResponse(Response r) {
        // success
    }

    @Override
    public void onFailure(Error e) {
        // error
    }
});

Can someone point me in the direction on how I can handle this similarly in Swift 3? Thanks!

Harry
  • 772
  • 10
  • 32
  • 1
    There are a lot of similar questions. You can use [completion handlers](https://stackoverflow.com/questions/39643334/how-do-you-write-a-completion-handler-in-swift-3). – Vladimir88dev Sep 05 '17 at 23:49
  • @VladimirDinic Very helpful link. Thanks. By chance, do you know if it's possible have multiple completionHandlers for one function? i.e. one for success and one for failure. I could pass back an object that could handle both scenarios - just wondering if it's possible – Harry Sep 05 '17 at 23:57
  • @Harry For completness sake, it's probably worth mentioning that this sort of pattern is possible in Swift/ObjC, thought with different terms. Interfaces are called protocols, and protocols that serve such a purpose (of receiving back information via methods called on your behalf) are typically called delegates. – Alexander Sep 06 '17 at 04:14

1 Answers1

2

It's possible to have multiple completion handlers. Here is a short example:

func request(url:String, success:@escaping(Any) -> Void, failure:@escaping(Any?) -> Void)
{
    let task = URLSession.shared.dataTask(with: URL.init(string: url)!) { (data, response, error) in
        if let responseError = error
        {
            failure(responseError)
        }
        else if let responseData = data  //Make additional checks if there is an error
        {
            success(responseData)  //Call when you are sure that there is no error
        }
        else
        {
            failure(nil)
        }
    }
    task.resume()
}

Example of usage:

self.request(url: "https://jsonplaceholder.typicode.com/posts", success: { (data) in
        //Do if success
    }) { (error) in
        //Do if error
    }
Vladimir88dev
  • 733
  • 1
  • 10
  • 19
  • You shouldn't check for `nil` (`data == nil`), only to force unwrap (`data!`). Use conditional binding instead. I'll up vote once you improve your answer – Alexander Sep 06 '17 at 02:19
  • You're right that conditional binding is a cleaner solution, so I've edited my answer. The focus on this question was on completion handlers, so I just gave a short example how to check for errors, i.e.where to start from. – Vladimir88dev Sep 06 '17 at 07:33
  • Nice. That shouldn't mean we can lose focus on other important things, like properly handling optionals – Alexander Sep 06 '17 at 13:42