我一直在尝试实现单例,以用作我从网络上传到我的iOS应用的照片的缓存。我在下面的代码中附加了三个变体。我试图使版本2正常工作,但是它导致了我不理解的编译器错误,并希望就我做错的事情寻求帮助。变体1进行缓存,但我不喜欢使用全局变量。变体3并没有进行实际的缓存,我相信这是因为我在赋给var ic = ....的赋值中获得了副本,对吗?
任何反馈和见解将不胜感激。
谢谢Zvi
import UIKit private var imageCache: [String: UIImage?] = [String : UIImage?]() class ImageCache { class var imageCache: [String : UIImage?] { struct Static { static var instance: [String : UIImage?]? static var token: dispatch_once_t = 0 } dispatch_once(&Static.token) { Static.instance = [String : UIImage?]() } return Static.instance! } } class ViewController: UIViewController { @IBOutlet weak var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() imageView.image = UIImage(data: NSData(contentsOfURL: NSURL(string: "http://images.apple.com/v/iphone-5s/gallery/a/images/download/photo_1.jpg")!)!) //variant 1 - this code is working imageCache["photo_1"] = imageView.image NSLog(imageCache["photo_1"] == nil ? "no good" : "cached") //variant 2 - causing a compiler error on next line: '@lvalue $T7' is not identical to '(String, UIImage?)' //ImageCache.imageCache["photo_1"] = imageView.image //NSLog(ImageCache.imageCache["photo_1"] == nil ? "no good" : "cached") //variant 3 - not doing the caching //var ic = ImageCache.imageCache //ic["photo_1)"] = imageView.image //NSLog(ImageCache.imageCache["photo_1"] == nil ? "no good" : "cached") } }
标准的单例模式为:
final class Manager { static let shared = Manager() private init() { ... } func foo() { ... } }
您将像这样使用它:
Manager.shared.foo()
感谢appzYourLife指出应该声明它final以确保它不会被意外子类化,以及private对初始值设定项使用access修饰符,以确保您不会意外地实例化另一个实例。
final
private
因此,回到图像缓存问题,您将使用以下单例模式:
final class ImageCache { static let shared = ImageCache() /// Private image cache. private var cache = [String: UIImage]() // Note, this is `private` to avoid subclassing this; singletons shouldn't be subclassed. private init() { } /// Subscript operator to retrieve and update cache subscript(key: String) -> UIImage? { get { return cache[key] } set (newValue) { cache[key] = newValue } } }
那么你就可以:
ImageCache.shared["photo1"] = image let image2 = ImageCache.shared["photo2"])
要么
let cache = ImageCache.shared cache["photo1"] = image let image2 = cache["photo2"]
上面显示了简单的单例缓存实现后,我们应该注意,您可能想要(a)通过使用使其线程安全NSCache;(b)应对记忆压力。因此,实际的实现类似于Swift 3中的以下内容:
NSCache
final class ImageCache: NSCache<AnyObject, UIImage> { static let shared = ImageCache() /// Observer for `UIApplicationDidReceiveMemoryWarningNotification`. private var memoryWarningObserver: NSObjectProtocol! /// Note, this is `private` to avoid subclassing this; singletons shouldn't be subclassed. /// /// Add observer to purge cache upon memory pressure. private override init() { super.init() memoryWarningObserver = NotificationCenter.default.addObserver(forName: .UIApplicationDidReceiveMemoryWarning, object: nil, queue: nil) { [weak self] notification in self?.removeAllObjects() } } /// The singleton will never be deallocated, but as a matter of defensive programming (in case this is /// later refactored to not be a singleton), let's remove the observer if deallocated. deinit { NotificationCenter.default.removeObserver(memoryWarningObserver) } /// Subscript operation to retrieve and update subscript(key: String) -> UIImage? { get { return object(forKey: key as AnyObject) } set (newValue) { if let object = newValue { setObject(object, forKey: key as AnyObject) } else { removeObject(forKey: key as AnyObject) } } } }
您将按以下方式使用它:
ImageCache.shared["foo"] = image
和
let image = ImageCache.shared["foo"]