2014-11-04 19 views
8

Tôi đã cố gắng triển khai một singleton được sử dụng làm bộ nhớ cache cho ảnh mà tôi đã tải lên ứng dụng iOS của mình từ web. Tôi đã đính kèm ba biến thể trong mã bên dưới. Tôi đã cố gắng để có được biến thể 2 làm việc nhưng nó gây ra một lỗi biên dịch mà tôi không hiểu và muốn được giúp đỡ về những gì tôi đang làm sai. Biến thể 1 làm bộ nhớ đệm nhưng tôi không thích việc sử dụng một biến toàn cục. Biến thể 3 không làm bộ nhớ đệm thực tế và tôi tin rằng đó là bởi vì tôi đang nhận được một bản sao trong nhiệm vụ để var ic = ...., đó là chính xác?Singleton in Swift

Mọi phản hồi và thông tin chi tiết sẽ được đánh giá cao.

Cảm ơn, 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") 
    } 
} 
+0

Tại sao bạn đang sử dụng '[String:? UIImage]' thay vì '[Chuỗi : UIImage] '? Tôi nghĩ đó có thể là nguồn gốc của rắc rối bạn đang gặp phải. –

+0

Lưu ý rằng bạn không cần phải sử dụng 'dispatch_once' - đọc [ở đây] (http://stackoverflow.com/a/26376288/148357) – Antonio

+0

chỉ FTR, DLImageLoader là một thư viện bộ nhớ đệm đáng kinh ngạc, và bây giờ là trong Swift. nó vô giá ... – Fattie

Trả lời

20

Các mô hình singleton giữa các ý kiến:

final class Manager { 
    static let shared = Manager() 

    private init() { ... } 

    func foo() { ... } 
} 

Và bạn muốn sử dụng nó như vậy:

Manager.shared.foo() 

tín dụng để appzYourLife để chỉ ra người ta nên khai báo nó final để chắc chắn rằng nó không phải là vô tình subc lassed cũng như việc sử dụng công cụ sửa đổi truy cập private cho trình khởi tạo, để đảm bảo bạn không vô tình khởi tạo một phiên bản khác. Xem https://stackoverflow.com/a/38793747/1271826.

Vì vậy, trở về câu hỏi bộ nhớ cache hình ảnh của bạn, bạn sẽ sử dụng Singleton pattern này:

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 
     } 
    } 
} 

Sau đó, bạn có thể:

ImageCache.shared["photo1"] = image 
let image2 = ImageCache.shared["photo2"]) 

Hoặc

let cache = ImageCache.shared 
cache["photo1"] = image 
let image2 = cache["photo2"] 

Sau khi thể hiện một đơn giản thực hiện bộ nhớ cache singleton ở trên, chúng ta nên lưu ý rằng bạn có thể muốn (a) làm cho nó thread an toàn bởi u hát NSCache; và (b) đáp ứng với áp lực bộ nhớ. Vì vậy, việc thực hiện thực tế là một cái gì đó như sau trong 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) 
      } 
     } 
    } 

} 

Và bạn muốn sử dụng nó như sau:

ImageCache.shared["foo"] = image 

let image = ImageCache.shared["foo"] 

Đối Swift 2.3 Ví dụ, xem previous revision câu trả lời này.

+1

Rob, cảm ơn bạn rất nhiều! – zvweiss

+0

Cảm ơn Rob, giải pháp của bạn rất tuyệt. Bạn có biết nếu có thể giữ chúng giữa các lần ra mắt không? Với NSUserDefaults chẳng hạn? Tôi không chắc đây là giải pháp tốt nhất. –

+1

@MarieDm - 'NSUserDefaults' có lẽ không phải là nơi thích hợp cho loại nội dung này. Tôi tự viết các công cụ vào '.CachesDirectory' (từ phương thức' NSFileManager' 'URLForDirectory' hoặc trong' NSSearchPathForDirectoriesInDomains'). BTW, câu trả lời này được đặt trước Swift 1.2, nhưng tôi đã sửa đổi nó với mẫu đơn giản hơn có thể có trong các phiên bản hiện tại của Swift. – Rob

1

Sau đây là hai cách tiếp cận khác nhau để tạo ra lớp singleton của bạn trong nhanh chóng 2,0

Tiếp cận 1) Cách tiếp cận này là thực hiện C Mục tiêu qua nhanh chóng.

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") 
     } 
} 

Tiếp cận 2) Một dòng Singleton, Đừng quên để thực hiện các init tư nhân (hạn chế sử dụng chỉ singleton)

import UIKit 

class SomeManager: NSObject { 

     static let sharedInstance = SomeManager() 

     private override init() { 

     } 

     func someMethod(){ 
      print("Some method call") 
     } 
    } 

Gọi phương pháp Singleton như:

SomeManager.sharedInstance.someMethod() 
0

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!") 
    } 
} 

Gọi một số Phương pháp:

SomeClass.sharedInstance.sayHello() //--> "Hello" 

Gọi một số phương pháp bằng cách tạo ra một cá thể của lớp mới (không):

SomeClass().sayHello() //--> 'SomeClass' cannot be constructed it has no accessible initailizers