Here is a simple snippet on how you should use completionHandlers
func loadImageAsync(completion: @escaping (UIImage?, Error?) -> Void) {
guard let url = URL(string: "https://rickandmortyapi.com/api/character/avatar/2.jpeg") else {
return
}
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else {
DispatchQueue.main.async {
completion(nil, error)
}
return
}
let image = UIImage(data: data)
DispatchQueue.main.async {
completion(image, nil)
}
}.resume()
}
See whats happening here? After the download occurs, we tell the main thread to dispatch our result. That's when we call the completion handler. That's like "Hey, i'm done, do whatever you want with these results."
Also important: UI updates should ALWAYS happen on the main thread.
Of course the syntax is a little different from what you're using but the principle is the same.
And the usage should be something like:
loadImageAsync { [weak self] img, err in
if let image = img {
self?.imageContainer.image = image
} else {
print("error \(String(describing: err))")
}
}
You should always use weak self or unowned self when possible, it prevent weird crashes and and memory leaks.
Also, try to nest the if let when possible, it reduces the cognitives complexity and makes your code more readable.
So, instead of this:
if let image = UIImage(data: data!){
if let cgimage = image.cgImage {
//...
}
}
Try something like:
if let data = data, let image = UImage(data: data), let cgImage = image.cgImage {
//...
}
And you should never, ever force unwrap a property unless you are 100% sure it has something in it. Try unwraping it using guard let or if let for your own security.
Post
Replies
Boosts
Views
Activity
You can use completion handler for this specific use case.
Take a look at this: https://firebase.blog/posts/2018/07/swift-closures-and-firebase-handling
Maybe it will help you