我一直在尝试实现一个单例,以用作我从网络上传到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")
}
}
以下是在swift 2.0中创建单例类的两种不同方法
方法1)该方法是通过swift实施的目标C。
import UIKit
class SomeManager: NSObject {
class var sharedInstance : SomeManager {
struct managerStruct {
static var onceToken : dispatch_once_t = 0
static var sharedObject : SomeManager? = nil
}
dispatch_once(&managerStruct.onceToken) { () -> Void in
managerStruct.sharedObject = SomeManager()
}
return managerStruct.sharedObject!
}
func someMethod(){
print("Some method call")
}
}
方法2)一行singleton,不要忘记实现私有init(限制只使用Singleton)
import UIKit
class SomeManager: NSObject {
static let sharedInstance = SomeManager()
private override init() {
}
func someMethod(){
print("Some method call")
}
}
调用单例方法,如:
SomeManager.sharedInstance.someMethod()
Swift 3:
class SomeClass
{
static let sharedInstance = SomeClass()
fileprivate override init() {
//This prevents others from using the default '()' initializer
super.init()
}
func sayHello()
{
print("Hello!")
}
}
调用一些方法:
SomeClass.sharedInstance.sayHello() //--> "Hello"
通过创建新的类实例来调用某个方法(失败):
SomeClass().sayHello() //--> 'SomeClass' cannot be constructed it has no accessible initailizers
标准的单例模式是:
final class Manager {
static let shared = Manager()
private init() { ... }
func foo() { ... }
}
你可以这样使用它:
Manager.shared.foo()
值得称赞的是,appzYourLife指出应该将它声明为< code>final以确保它不会意外地被子类化,并为初始值设定项使用< code>private访问修饰符,以确保不会意外地实例化另一个实例。参见https://stackoverflow.com/a/38793747/1271826.
因此,回到您的图像缓存问题,您将使用这种单例模式:
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 中的以下内容:
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"]
有关Swift 2.3的示例,请参见本答案的先前版本。
问题内容: 我正在学习Swift,还有另一个问题。Swift中是否有常规的epression,如果有,我该如何使用它们? 在研究中,我发现了一些相互矛盾的信息。Apple Developer文档中 有提及RegEx的内容,但它与我见过的任何其他语言看起来都非常不同。如果这是解决方案,该如何使用? 另一方面,该网站建议RegEx在Swift中不存在。这样对吗? 如果有帮助,我尝试使用正则表达式从包含
问题内容: 我正在尝试在Swift中创建字符串的HMAC SHA-1哈希,但是由于它似乎没有导入CommonCrypto框架,因此无法弄清楚如何与API进行交互。我尝试了各种不同形式的“ import CommonCrypto”并创建了一个桥接头文件,但没有一个起作用。 奇怪的是,如果我创建一个Objective-C类,那么我就可以与API交互而不会出现任何问题,因此这似乎是Swift特有的。 另
问题内容: Swift当前是否支持宏,或者将来有计划添加支持吗?目前,我正在散布: 在我的代码中的各个地方。 问题答案: 在这种情况下,应为“宏”参数添加默认值。 Swift 2.2及更高版本 Swift 2.1及更低版本 这是和功能做。 除了其他答案中已经提到的条件编译之外,没有其他宏。
问题内容: 我正在努力弄清楚此代码段出了什么问题。目前这在Objective- C中有效,但是在Swift中这只是在方法的第一行崩溃。它在控制台日志中显示错误消息:。 问题答案: 另请参阅马特的答案,其中包含解决方案的后半部分 让我们找到一个无需创建自定义子类或笔尖的解决方案 真正的问题在于,Swift区分可以为空()的对象和不能为空的对象。如果您没有为标识符注册笔尖,则可以返回。 这意味着我们必
问题内容: 我正在尝试创建一个in,但是遇到了一些麻烦。 是同一个类中的函数。 我在编辑器中遇到错误: 找不到接受提供的参数的’init’的重载 当我更改为错误时消失。 我试过了: 但是没有任何效果,我在参考文献中找不到解决方案。 问题答案: Swift 本身 不使用选择器-在Objective-C中,使用选择器的几种设计模式在Swift中的工作方式有所不同。(例如,在协议类型或/ 测试上使用可选
问题内容: 我在Swift中使用“ NSTimer.scheduledTimerWithTimeInterval”看到的所有示例都使用“ target:self”参数显示,但不幸的是,这在Swift Playgrounds中无法直接使用。 这是上面引用的导致错误的示例: 问题答案: 这些天您真的不应该使用。它消耗大量资源,导致不必要的电池消耗,并且该API使自己变得丑陋。 使用来代替: 当然,由于