1
\$\begingroup\$

I want to wrap NSCache in a Singleton in order to use dependency injection in my code. This has resulted, rather unfortunately, in passing the type through a function parameter, and I even need two mocks for success and failure since it is a singleton instance.

I think there might be a better way, but any comments appreciated!

ImageCache and protocol

protocol ImageCacheProtocol {
    static var shared: Self { get }
    func getCache() -> NSCache<AnyObject, UIImage>
}

final class ImageCache: ImageCacheProtocol {
    var cache: NSCache<AnyObject, UIImage> = NSCache<AnyObject, UIImage>()

    public static let shared = ImageCache()
    private init() {}
    
    func getCache() -> NSCache<AnyObject, UIImage> {
        return cache
    }
}

MockImageCache & MockImageCacheFailure

final class MockImageCache: ImageCacheProtocol {
    var cache: NSCache<AnyObject, UIImage> = MockNSCache(shouldReturnImage: true)

    public static let shared = MockImageCache()
    private init() {}

    func getCache() -> NSCache<AnyObject, UIImage> {
        return cache
    }
}


final class MockImageCacheFailure: ImageCacheProtocol {
    var cache: NSCache<AnyObject, UIImage> = MockNSCache(shouldReturnImage: false)

    public static let shared = MockImageCacheFailure()
    private init() {}

    func getCache() -> NSCache<AnyObject, UIImage> {
        return cache
    }
}

Instantiating my view model (snippet)

class ViewModel<U: ImageCacheProtocol> {

    private var cache: U.Type
    init<T: NetworkManagerProtocol>(networkManager: T, data: DisplayContent, imageCache: U.Type) {
        self.networkManager = AnyNetworkManager(manager: networkManager)
        
        cache = imageCache
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Yes, this isn't the canonical way. My solution is to not use Self and to instead focus on shared.

That is:

protocol ImageCacheProtocol {
    func getCache() -> NSCache<AnyObject, UIImage>
}

final class ImageCache: ImageCacheProtocol {
    var cache: NSCache<AnyObject, UIImage> = NSCache<AnyObject, UIImage>()
    static var shared = ImageCache()
    
    private init() {}
    
    func getCache() -> NSCache<AnyObject, UIImage> {
        return cache
    }
}

Then the mocks can be altered:

final class MockImageCache: ImageCacheProtocol {
    var cache: NSCache<AnyObject, UIImage> = MockNSCache(shouldReturnImage: true)
    public static var shared: ImageCacheProtocol! = MockImageCache()
    func getCache() -> NSCache<AnyObject, UIImage> {
        return cache
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.