Я хочу получить доступ к NSCache из более чем одного места в моем приложении, так как я использую его для кеширования изображений из конечной точки API.

Например, табличное представление 4 и viewcontroller 6 на диаграмме ниже используют одни и те же изображения, поэтому я не хочу загружать их дважды.

enter image description here

Возможные решения:

  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? Так...

  2. Используйте внедрение зависимостей. Но мы находимся в контроллере представления вкладок, разве это не то же самое, что 2?

Я не уверен, что здесь правильная стратегия, поэтому я спрашиваю, можно ли здесь использовать другой метод.

Что я сделал Создал приложение на примере с использованием NSCache и исследовал одноэлементное решение. Я пытался использовать инъекцию зависимостей, но думаю, что это не имеет смысла. Я просмотрел переполнение стека и документацию, но для этого конкретного обстоятельства я не нашел потенциальных решений.

То, что я привел . Минимальный пример с диаграммой и проверенным решением, которым я не удовлетворен.

Что бесполезно , так это ответы, в которых говорится, что NSCache неверен, или об использовании библиотек. Я пытаюсь использовать NSCache для собственного обучения, это не домашнее задание, и я хочу решить этот конкретный случай этой проблемы в этой структуре приложения.

В чем вопрос? Как избежать использования синглтона в этом случае контроллеры представления в контроллере представления вкладок.

1
WishIHadThreeGuns 2 Апр 2019 в 12:02

1 ответ

Лучший ответ

Во-первых. Синглтоны по своей сути неплохие. Они могут затруднить тестирование вашего кода и действуют как магниты зависимости.

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

2
Warren Burton 2 Апр 2019 в 11:41