Singleton in Swift

后端 未结 4 1612
盖世英雄少女心
盖世英雄少女心 2020-11-28 08:45

I\'ve been trying to implement a singleton to be used as a cache for photos which I uploaded to my iOS app from the web. I\'ve attached three variants in the code below. I

相关标签:
4条回答
  • 2020-11-28 09:18

    Swift-5

    To create a singleton class:

    import UIKit
    
    final class SharedData: NSObject {
       static let sharedInstance = SharedData()
    
       private override init() { }
    
       func methodName() { }
    }
    

    To access

    let sharedClass = SharedClass.sharedInstance
    

    OR

    SharedClass.sharedInstance.methodName()
    
    0 讨论(0)
  • 2020-11-28 09:32

    The standard singleton pattern is:

    final class Manager {
        static let shared = Manager()
    
        private init() { ... }
    
        func foo() { ... }
    }
    

    And you'd use it like so:

    Manager.shared.foo()
    

    Credit to appzYourLife for pointing out that one should declare it final to make sure it's not accidentally subclassed as well as the use of the private access modifier for the initializer, to ensure you don't accidentally instantiate another instance. See https://stackoverflow.com/a/38793747/1271826.

    So, returning to your image cache question, you would use this singleton pattern:

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

    Then you can:

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

    Or

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

    Having shown a simplistic singleton cache implementation above, we should note that you probably want to (a) make it thread safe by using NSCache; and (b) respond to memory pressure. So, the actual implementation is something like the following in 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)
                }
            }
        }
    
    }
    

    And you'd use it as follows:

    ImageCache.shared["foo"] = image
    

    And

    let image = ImageCache.shared["foo"]
    

    For Swift 2.3 example, see previous revision of this answer.

    0 讨论(0)
  • 2020-11-28 09:33

    Following are the two different approaches to create your singleton class in swift 2.0

    Approach 1) This approach is Objective C implementation over swift.

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

    Approach 2) One line Singleton, Don't forget to implement the Private init (restrict usage of only singleton)

    import UIKit
    
    class SomeManager: NSObject {
    
           static let sharedInstance = SomeManager()
    
           private override init() {
    
           }
    
           func someMethod(){
                print("Some method call")
           }
      }
    

    Call the Singleton method like :

      SomeManager.sharedInstance.someMethod()
    
    0 讨论(0)
  • 2020-11-28 09:36

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

    Invoke some Method:

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

    Invoke some Method by creating a new class instance (fails):

    SomeClass().sayHello() //--> 'SomeClass' cannot be constructed it has no accessible initailizers
    
    0 讨论(0)
提交回复
热议问题