/// Interface that fetches image from a source. /// Image can be fetched from a web service or even from a local source. internal protocol ImageFetcher { func fetch(then completion: @escaping (UIImage?, Error?) -> Void) } /// ImageFetcher implementation to fetch image from web service internal class ImageDownloader: ImageFetcher { let url: URL init(url: URL) { self.url = url } func fetch(then completion: @escaping (UIImage?, Error?) -> Void) { // URL Operation // Call completion(image, error) } } /// ImageFetcher implementation to fetch image from the documents directory internal class ImageFileFetcher: ImageFetcher { let imageName: String init(imageName: String){ self.imageName = imageName } func fetch(then completion: @escaping (UIImage?, Error?) -> Void) { // FileManager operation to get image from the saved document directory. // Call completion(image, error) } } ///////////////////////////////////////////// /// Similarly you can have ImageFetcher to mock all these use cases to test our User class implementation. ///////////////////////////////////////////// /// User Model public class User { // Stores the public var name: String /// Private image holder for the user. /// Nil either when image is not there or not fetched. var iProfileImage: UIImage? /// Display profile image for the user. /// Returns either the actual user profile image or the default display image. public var profileImage: UIImage { return iProfileImage ?? .defaultProfileImage } init(name:String) { self.name = name } func fetchProfileImage(fetcher: ImageFetcher, then completion: @escaping (Bool)-> Void) { fetcher.fetch { (image, error) in if let fetchError = error { print("Failed to fetch Image with error - \(fetchError)") completion(false) } else if let fetchedImage = image { print("Image fetched") self.iProfileImage = fetchedImage completion(true) } else { print("Failed to fetch Image with unknown error") completion(false) } } } }