swift 在选项卡视图控制器中跨视图控制器访问NSCache

q7solyqu  于 2022-12-10  发布在  Swift
关注(0)|答案(2)|浏览(239)

我想从我的APP中的多个位置访问NSCache,因为我正在使用它来缓存来自API端点的图像。
例如,下图中的表视图4和视图控制器6使用相同的图像,因此我不想下载它们两次。

候选解决方案:
1.单例

class Cache {  

    private static var sharedCache: NSCache<AnyObject, AnyObject>?        
    static public func getCache () -> NSCache<AnyObject, AnyObject> {

        if sharedCache == nil {
            self.sharedCache = NSCache()
        }
        return sharedCache!
    } 
}

看起来很好,但是“单身者不好”所以...
1.该高速缓存存储在TabViewController中
这将视图与视图控制器紧密耦合,因此...
1.存储在AppDelegate中。但这不是和1一样吗?所以...
1.使用依赖注入。但是我们在一个标签视图控制器中,所以这不是和2一样吗?
我不知道这里的正确策略,所以我问是否有另一种方法可以在这里使用。

我做了什么创建了一个应用程序,其中包含一个使用NSCache的示例,并探索了一个单例解决方案。我尝试使用依赖注入,但认为它没有意义。我查看了堆栈溢出和文档,但对于这种特定情况,我没有找到潜在的解决方案。
我给出的内容一个最小的示例,带有一个图表和一个我不满意的测试解决方案。
什么是没有帮助的是说NSCache是不正确的答案,或使用库。我试图使用NSCache为我自己的学习,这不是家庭作业,我想解决这个问题的这个特定示例在这个应用程序结构。
问题是什么如何避免在此示例中使用单例,在选项卡视图控制器中使用视图控制器。

egmofgnx

egmofgnx1#

首先,单例并不是天生的坏,它们会让你的代码很难测试,而且它们确实起到了依赖磁铁的作用。
单例对于作为工具的类是很好的,例如NSFileManager aka FileManger,即不携带状态或数据的类。
一个很好的替代方法是依赖注入,但是对于视图控制器和故事板来说,这可能很难,而且感觉非常简单。
一种可能的方法是声明一个描述类似缓存的接口的protocol

protocol CacheProtocol: class {
    func doCacheThing()
}

class Cache: CacheProtocol {
    func doCacheThing() {
        //
    }
}

然后声明一个protocol,所有希望使用该缓存的对象都可以使用它。

protocol CacheConsumer: class {
    var cache: CacheProtocol? { get set }
    func injectCache(to object: AnyObject)
}

extension CacheConsumer {
    func injectCache(to object: AnyObject) {
        if let consumer = object as? CacheConsumer {
            consumer.cache = cache
        }
    }
}

最后,在顶层创建该缓存的具体示例。

/// Top most controller
class RootLevelViewController: UIViewController, CacheConsumer {
    var cache: CacheProtocol? = Cache()

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        injectCache(to: segue.destination)
    }

}

您可以该高速缓存沿prepareForSegue中的缓存线向下传递。
或者您可以使用精细的子类化来创建一致性。

class MyTabBarController: UITabBarController, CacheConsumer {
    var cache: CacheProtocol?
}

或者,您可以使用委托方法来获得向下广播该高速缓存对象。

extension RootLevelViewController: UITabBarControllerDelegate {
    func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
        injectCache(to: viewController)
    }
}

现在您有了一个系统,其中任何CacheConsumer都可以使用该高速缓存并将其向下传递给任何其他对象。

ccrfmcuu

ccrfmcuu2#

如果你使用coordinator模式,你可以在coordinator中保存导航流该高速缓存,并从那里/init使用缓存访问它。它也可以很好地工作,因为当导航流被删除时,缓存也会被删除。

final class SomeCoordinator: NSObject, Coordinator {
    var rootViewController: UINavigationController
    var myCache = NSCache<AnyObject, AnyObject>()
    
    override init() {
        self.rootViewController = UINavigationController()
        super.init()
    }
    
    func start() {
        let vc = VC1(cache: myCache)
        vc.coordinator = self
        rootViewController.setViewControllers([vc], animated: false)
        parentCoordinator?.rootViewController.present(rootViewController, animated: true)
    }
    
    func goToVC2() {
        let vc = VC2(cache: myCache)
        vc.coordinator = self
        rootViewController.pushViewController(vc, animated: true)
    }
    
    func goToVC3() {
        let vc = VC3(cache: myCache)
        vc.coordinator = self
        rootViewController.present(vc, animated: true)
    }
    
    func goToVC4() {
        let vc = VC4(cache: myCache)
        vc.coordinator = self
        rootViewController.present(vc, animated: true)
    }
    
    deinit {
        print("✅ Deinit SomeCoordinator")
    }
    
}

相关问题