Reputation: 1
I've run into a problem.
I've made a service for API calls that returns a User
object, and the API call works fine and it returns the User
object.
However, I need to use completion and @escaping, and I'm not sure how to do it properly, since I'm new to Swift and iOS development.
The Code is below.
func login(with credentials: LoginCredentials) {
let params = credentials
AF.request(Service.baseURL.appending("/user/login"), method: .post, parameters: params, encoder: JSONParameterEncoder.default).responseJSON { response in
switch response.result {
case .success:
print("Success")
case.failure:
print("Fail")
}
}
Also, how do I call a function when there is completion?
Upvotes: 0
Views: 1682
Reputation: 344
It’s not clear what kind of argument (if it takes one) the completion for your method shall take, thus I’m gonna give you a couple of hints. Perhaps you want to also have the completion for your method execute on a queue specified as parameter in the call. Therefore you might structure your method’s signature in this way:
func login(with credentials: LoginCredentials, queue: DispatchQueue = .main, _ completion: @esacping (Bool) -> Void)
Here I’ve used the type Bool
as argument for the completion to be executed, and defaulted the queue argument to be .main
, assuming that you’re just interested in deliver as result argument in the completion a value of true
in case you’ve gotten a .success
response, false
otherwise; I’m also assuming that this method will mainly be called with the completion being executed on the main thread for updating a state, hence the default value for the queue
argument.
Therefore your method body could become like this:
func login(with credentials: LoginCredentials, queue: DispatchQueue = .main, _ completion: @escaping (Bool) -> Void) {
let params = credentials
AF.request(
Service.baseURL.appending("/user/login"),
method: .post,
parameters: params,
encoder: JSONParameterEncoder.default
).responseJSON { response in
switch response.result {
case .success:
queue.async { completion(true) }
case.failure:
queue.async { completion(false) }
}
}
Now of course if you need to deliver something different (as in the token for the login session and an error in case of failure) then you’d better adopt a Result<T,Error>
Swift enum as argument to pass to the completion.
Without you giving more details in these regards, I can only give a generic suggestion for this matter, cause I cannot go into the specifics.
EDIT
As a bonus I'm also adding how you could structure this method with the new Swift concurrency model:
// Assuming you are returning either a value of type User or
// throwing an error in case the login failed (as per your comments):
func login(with credentials: LoginCredentials) async throws -> User {
withCheckedThrowingContinuation { continuation in
AF.request(
Service.baseURL.appending("/user/login"),
method: .post,
parameters: credentials,
encoder: JSONParameterEncoder.default
).responseJSON { response in
switch response.result {
case .success:
let loggedUser = User(/* your logic to create the user to return*/)
continuation.resume(returning: loggedUser)
case.failure:
continuation.resume(throwing: User.Error.loginError)
}
}
}
// Here's possible way to implement the error on your User type
extension User {
enum Error: Swift.Error {
case loginError
// add more cases for other errors related to this type
}
}
Upvotes: 1