我真的需要单例上的共享实例吗?

Posted

技术标签:

【中文标题】我真的需要单例上的共享实例吗?【英文标题】:Do I really need a shared instance on a singleton? 【发布时间】:2016-01-04 15:08:16 【问题描述】:

我已经写了一个辅助结构来保存和加载东西到NSUserDefaults

import UIKit

struct Database 

    static let defaults = NSUserDefaults.standardUserDefaults()

    static var myVariable: AnyObject?

    static func save() 
        defaults.setObject(myVariable, forKey: "myVariable")
    

    static func load() 
        if let myVariable = defaults.objectForKey("myVariable") 
            self.myVariable = myVariable
        
    

    static func clear() 
        defaults.removeObjectForKey("myVariable")
    

现在我可以简单地使用Database.load()NSUSerDefaults 加载myVariable。 但是,使用此代码也可以实现相同的目标:

struct Database2 

    static var sharedInstance = Database()

    let defaults = NSUserDefaults.standardUserDefaults()

    var myVariable: AnyObject?

    func save() 
        defaults.setObject(myVariable, forKey: "myVariable")
    

    func load() 
        if let myVariable = defaults.objectForKey("myVariable") 
            self.myVariable = myVariable
        
    

    func clear() 
        defaults.removeObjectForKey("myVariable")
    

现在我会使用Database2.sharedInstance.load()

哪一个被认为是更好的做法,为什么? sharedInstance 有什么用,如果我可以使用 static 声明做任何我想做的事情?

【问题讨论】:

With the Objective-C/Swift Singleton model, why do we create a shared instance and not just use class methods?的可能重复 【参考方案1】:

推荐使用共享实例,至少出于以下原因:

    类方法使单元测试更难 你需要依赖注入的类实例 如果稍后您决定非单例更合适 - 例如你决定为“myVariable”设置两个持久性存储,然后你就卡住了 最后,类成员生活在全局空间中,我们应该避免使用全局变量

您应该问的真正问题是,您是否真的需要一个单例(有或没有共享实例)来解决您的问题。如果拥有单例的唯一原因是易于访问,那么您真的不需要单例。

P.S.有一个关于单例的非常好的article on objc.io,虽然它是为 Objective-C 编写的,但其中的许多概念也适用于 Swift。

【讨论】:

【参考方案2】:
// with singleton pattern, there exist only one copy of the object
// sigleton pattern can be applied for reference type only
// let st1 = Singleton(); let st2 = Sigleton(); st1 === st2

// in your example, S is value type. All instances of S share only type properties, here only i

struct S 
    static var i: Int = 100
    var j: Int
    func foo() 
        //print(i) // error: static member 'i' cannot be used on instance of type 'S'
        print(S.i)
    
    init(_ j: Int) 
        self.j = j
    


var s1 = S(1)
var s2 = S(2)
//s1.i // error: static member 'i' cannot be used on instance of type 'S'
S.i // 100
s1.foo() // 100
s1.j // 1
s2.foo() // 100
s2.j // 2
S.i = 200
s1.foo() // 200
s2.foo() // 200

顺便说一下,这种(你的)方法非常有用,在某些情况下可能是首选。

【讨论】:

以上是关于我真的需要单例上的共享实例吗?的主要内容,如果未能解决你的问题,请参考以下文章

iOS中的单例

你真的会写单例模式吗

你真的会写JAVA的单例模式吗?

(转)你真的会写单例模式吗——Java实现

你真的会写单例模式吗——Java实现

你是否真的理解单例模式?