Search code examples
swiftconcurrencyclosuresalamofire

Pros and Cons Alamofire Concurrency vs Regular or suggested method


Can some explain me the pros and cons about Alamofire Concurrency and Alamofire regular suggested method? Concurrency way

func getDataConcurrency() async throws -> SomeModel {
    let dataTask = AF.request("/getData")
        .validate()
        .serializingDecodable(SomeModel.self)
    let response = await dataTask.response
    
    switch response.result {
    case .success(let model):
        return SomeModel
    case .failure(let err):
        throw err
    }
}

Regular, default or suggested method by Alamofire

func getDataRegularMethod(completion: @escaping (Result<SomeModel, AFError>) -> Void) {
    AF.request("/getData")
    .validate()
    .responseDecodable(of: SomeModel.self) { response in
        switch response.result {
        case .success(let someModel):
            completion(.success(someModel))
        case .failure:
            completion(.failure(.someAFError)
        }
    }
}

Understand and chose the best option


Solution

  • In terms of pros of Swift concurrency, in general:

    • No completion handlers are needed (often making code easier to reason about);
    • No switch of Result types are needed anymore; and
    • It has more graceful support of cancelation.

    In terms of cons:

    • It requires apps targeting iOS 13 or macOS Catalina or later;
    • It requires Swift 5.6 or later and Xcode 13.3.1 or later (but this is probably moot, because as of April, “apps submitted to the App Store must be built with Xcode 14.1 or later” anyway);
    • If you use Swift concurrency, you probably want the whole project to use Swift concurrency and retire the GCD pattern … it is not generally advised to mix asynchronous patterns within the same project; and
    • If you are new to Swift concurrency, actors, async-await, Sendable types, etc., there is a bit of a learning curve.

    The cons tend to be more constraints than actual disadvantages. Bottom line, if you can use async-await, you probably should. But feel free to do whatever you want, and just be consistent (whether that be traditional completion-handler patterns, Combine, or Swift concurrency). But Swift concurrency is the emerging standard, so if you choose to use the legacy completion-handler patterns, you probably would need a pretty compelling case to so.

    Now, if you have already adopted async-await in your project and are simply wondering whether you should also adopt this pattern with Alamofire, too, the answer is, yes, you probably should. There is no downside and, as you will see below, it simplifies your code.


    FWIW, your Swift concurrency example can be further simplified:

    func getDataConcurrency(for url: URL) async throws -> SomeModel {
        try await AF.request(url)
            .validate()
            .serializingDecodable(SomeModel.self, automaticallyCancelling: true)
            .value
    }
    

    If the request succeeds, the value will be returned. If it fails, the error will be thrown. If you cancel the task, the requests will be automatically canceled. No completion handlers or switch statements are necessary.


    In you are interested in more information about Swift concurrency and its advantages, see WWDC 2021 video Meet async/await in Swift, as well as the other videos on that page.