Сначала. Синглтоны не плохо по своей природе. Они могут затруднить тестирование вашего кода, и они действуют как магниты зависимости.
Синглтоны хороши для классов, которые являются инструментами, например, NSFileManager
aka FileManger
, то есть что-то, что не несет состояния или данных.
Хорошей альтернативой является внедрение зависимостей, но с контроллерами представления и раскадровками это может быть сложно и чувствовать себя очень стандартно. В конечном итоге вы передаете все по линии в prepareForSegue
.
Один из возможных способов - объявить 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
может использовать кеш и передавать его под уклон любому другому объекту.