在Swift中使用dispatch_once单例模型

在Swift中使用dispatch_once单例模型,swift,singleton,dispatch,Swift,Singleton,Dispatch,我正在尝试为Swift中的使用制定一个合适的单例模型。到目前为止,我已经能够得到一个非线程安全模型: class var sharedInstance: TPScopeManager { get { struct Static { static var instance: TPScopeManager? = nil } if !Static.instance { Static.instanc

我正在尝试为Swift中的使用制定一个合适的单例模型。到目前为止,我已经能够得到一个非线程安全模型:

class var sharedInstance: TPScopeManager {
    get {
        struct Static {
            static var instance: TPScopeManager? = nil
        }

        if !Static.instance {
            Static.instance = TPScopeManager()
        }

        return Static.instance!
    }
}
在静态结构中包装singleton实例应该允许单个实例在没有复杂命名方案的情况下不会与singleton实例发生冲突,并且应该使事情相当私有。显然,这个模型并不安全线程。因此,我尝试在整个事件中添加
dispatch\u once

class var sharedInstance: TPScopeManager {
    get {
        struct Static {
            static var instance: TPScopeManager? = nil
            static var token: dispatch_once_t = 0
        }

        dispatch_once(Static.token) { Static.instance = TPScopeManager() }

        return Static.instance!
    }
}
但是我在
dispatch\u once
行上得到一个编译器错误:

无法将表达式的类型“Void”转换为类型“()”

我尝试了几种不同的语法变体,但它们似乎都有相同的结果:

dispatch_once(Static.token, { Static.instance = TPScopeManager() })

使用Swift的
dispatch\u once
的正确用法是什么?我最初认为问题出在错误消息中的
()
导致的块上,但我看得越多,就越觉得可能需要正确定义
调度。

对于Swift 1.2及更高版本:

class Singleton  {
   static let sharedInstance = Singleton()
}
有了正确性证明(所有的功劳),现在几乎没有理由使用任何以前的方法来处理单身汉

private let _singletonInstance = SingletonClass()
class SingletonClass {
  class var sharedInstance: SingletonClass {
    return _singletonInstance
  }
}
更新:现在这是定义单例的官方方法,如中所述

关于使用
static
vs
class
的问题<即使
class
变量可用,也应该使用code>static
。单例并不意味着子类化,因为这将导致基本单例的多个实例。使用
static
可以以一种漂亮、快捷的方式实现这一点

对于Swift 1.0和1.1:

class Singleton  {
   static let sharedInstance = Singleton()
}
随着Swift最近的变化,主要是新的访问控制方法,我现在倾向于更干净的方式,为单身人士使用全局变量

private let _singletonInstance = SingletonClass()
class SingletonClass {
  class var sharedInstance: SingletonClass {
    return _singletonInstance
  }
}
如Swift博客文章所述:

全局变量的惰性初始值设定项(也适用于 结构和枚举)在第一次访问全局时运行,并且 作为dispatch_启动一次,以确保初始化成功 原子的。这提供了一种在代码中一次性使用dispatch_的酷方法: 只需声明一个带有初始值设定项的全局变量并标记它 私人的


这种创建单例的方法是线程安全的、快速的、懒惰的,并且可以免费连接到ObjC。

查看Apple的示例代码,我发现了这种模式。我不确定Swift如何处理静态,但这在C#中是线程安全的。我包括Objective-C互操作的属性和方法

struct StaticRank {
    static let shared = RankMapping()
}

class func sharedInstance() -> RankMapping {
    return StaticRank.shared
}

class var shared:RankMapping {
    return StaticRank.shared
}

有一个更好的方法。您可以在类声明上方的类中声明全局变量,如下所示:

var tpScopeManagerSharedInstance = TPScopeManager()
这只调用默认的init或Swift中默认为
dispatch\u的init和全局变量。然后,在任何一个类中,您想要获得引用,只需执行以下操作:

var refrence = tpScopeManagerSharedInstance
// or you can just access properties and call methods directly
tpScopeManagerSharedInstance.someMethod()

因此,基本上你可以摆脱整个共享实例代码块。

既然苹果现在已经澄清静态结构变量都是惰性的,并且包装在
dispatch\u once
中(请参见本文末尾的注释),我想我的最终解决方案是:

class WithSingleton {
    class var sharedInstance: WithSingleton {
        struct Singleton {
            static let instance = WithSingleton()
        }

        return Singleton.instance
    }
}
这利用了静态结构元素的自动延迟、线程安全初始化,对使用者安全地隐藏了实际实现,保持了所有内容的紧凑划分以便于识别,并消除了可见的全局变量

苹果澄清了惰性初始值设定项是线程安全的,因此不需要
dispatch\u once
或类似的保护

全局变量的惰性初始值设定项(也用于结构和枚举的静态成员)在第一次访问全局变量时运行,并作为dispatch_启动一次,以确保初始化是原子的。这提供了一种在代码中一次性使用dispatch_的酷方法:只需使用初始值设定项声明一个全局变量并将其标记为private

使用:

class UtilSingleton: NSObject {

    var iVal: Int = 0

    class var shareInstance: UtilSingleton {
        get {
            struct Static {
                static var instance: UtilSingleton? = nil
                static var token: dispatch_once_t = 0
            }
            dispatch_once(&Static.token, {
                Static.instance = UtilSingleton()
            })
            return Static.instance!
        }
    }
}
如何使用:

UtilSingleton.shareInstance.iVal++
println("singleton new iVal = \(UtilSingleton.shareInstance.iVal)")

在看到David的实现之后,似乎没有必要使用单例类函数
instanceMethod
,因为
let
所做的事情与
sharedInstance
类方法几乎相同。你所需要做的就是将它声明为一个全局常量,这就是它

let gScopeManagerSharedInstance = ScopeManager()

class ScopeManager {
   // No need for a class method to return the shared instance. Use the gScopeManagerSharedInstance directly. 
}
tl;dr:如果您使用的是Swift 1.2或更高版本,请使用类常量方法;如果您需要支持早期版本,请使用嵌套结构方法

根据我使用Swift的经验,有三种方法可以实现支持延迟初始化和线程安全的单例模式

类常数 这种方法支持延迟初始化,因为Swift延迟初始化类常量(和变量),并且根据
let
的定义是线程安全的。现在,我们来实例化一个单例

Swift 1.2中引入了类常量。如果需要支持早期版本的Swift,请使用下面的嵌套结构方法或全局常量

嵌套结构 这里我们使用嵌套结构的静态常量作为类常量。这是Swift 1.1及更早版本中缺少静态类常量的一个变通方法,仍然是函数中缺少静态常量和变量的变通方法

派你一次 传统的Objective-C方法移植到Swift。我相当肯定,与嵌套结构方法相比没有任何优势,但我还是把它放在这里,因为我发现语法上的差异很有趣

class Singleton {
    class var sharedInstance: Singleton {
        struct Static {
            static var onceToken: dispatch_once_t = 0
            static var instance: Singleton? = nil
        }
        dispatch_once(&Static.onceToken) {
            Static.instance = Singleton()
        }
        return Static.instance!
    }
}

有关单元测试,请参阅此项目。

我更喜欢此实现:

class APIClient {

}

var sharedAPIClient: APIClient = {
    return APIClient()
}()

extension APIClient {
    class func sharedClient() -> APIClient {
        return sharedAPIClient
    }
}

如果您计划在Objective-C中使用Swift singleton类,此设置将使编译器生成适当的Objective-C类标头:

然后,在Objective-C课程中,你可以像在Swift之前那样给你的单身汉打电话:

[ImageStore sharedStore];
这个
[ImageStore sharedStore];
enum SharedTPScopeManager: TPScopeManager {
    case Singleton
}
import Foundation

class ItemStore: NSObject {

    class var sharedStore : ItemStore {
        struct Singleton {
            // lazily initiated, thread-safe from "let"
            static let instance = ItemStore()
        }
        return Singleton.instance
    }

    var _privateItems = Item[]()
    // The allItems property can't be changed by other objects
    var allItems: Item[] {
        return _privateItems
    }

    init() {
        super.init()
        let path = itemArchivePath
        // Returns "nil" if there is no file at the path
        let unarchivedItems : AnyObject! = NSKeyedUnarchiver.unarchiveObjectWithFile(path)

        // If there were archived items saved, set _privateItems for the shared store equal to that
        if unarchivedItems {
            _privateItems = unarchivedItems as Array<Item>
        } 

        delayOnMainQueueFor(numberOfSeconds: 0.1, action: {
            assert(self === ItemStore.sharedStore, "Only one instance of ItemStore allowed!")
        })
    }

    func createItem() -> Item {
        let item = Item.randomItem()
        _privateItems.append(item)
        return item
    }

    func removeItem(item: Item) {
        for (index, element) in enumerate(_privateItems) {
            if element === item {
                _privateItems.removeAtIndex(index)
                // Delete an items image from the image store when the item is 
                // getting deleted
                ImageStore.sharedStore.deleteImageForKey(item.itemKey)
            }
        }
    }

    func moveItemAtIndex(fromIndex: Int, toIndex: Int) {
        _privateItems.moveObjectAtIndex(fromIndex, toIndex: toIndex)
    }

    var itemArchivePath: String {
        // Create a filepath for archiving
        let documentDirectories = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
        // Get the one document directory from that list
        let documentDirectory = documentDirectories[0] as String
        // append with the items.archive file name, then return
        return documentDirectory.stringByAppendingPathComponent("items.archive")
    }

    func saveChanges() -> Bool {
        let path = itemArchivePath
        // Return "true" on success
        return NSKeyedArchiver.archiveRootObject(_privateItems, toFile: path)
    }
}
import Foundation
import UIKit

typealias completionBlock = () -> ()

extension Array {
    func contains(#object:AnyObject) -> Bool {
        return self.bridgeToObjectiveC().containsObject(object)
    }

    func indexOf(#object:AnyObject) -> Int {
        return self.bridgeToObjectiveC().indexOfObject(object)
    }

    mutating func moveObjectAtIndex(fromIndex: Int, toIndex: Int) {
        if ((fromIndex == toIndex) || (fromIndex > self.count) ||
            (toIndex > self.count)) {
                return
        }
        // Get object being moved so it can be re-inserted
        let object = self[fromIndex]

        // Remove object from array
        self.removeAtIndex(fromIndex)

        // Insert object in array at new location
        self.insert(object, atIndex: toIndex)
    }
}

func delayOnMainQueueFor(numberOfSeconds delay:Double, action closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue()) {
            closure()
    }
}
import Foundation

    let ConfigurationManagerSharedInstance = ConfigurationManager()
 class ConfigurationManager : NSObject {
    var globalDic: NSMutableDictionary = NSMutableDictionary()

class var sharedInstance:ConfigurationManager {
    return ConfigurationManagerSharedInstance

}

init() {

    super.init()

    println ("Config Init been Initiated, this will be called only onece irrespective of many calls")   

}
 println(ConfigurationManager.sharedInstance.globalDic)  
 ConfigurationManager.sharedInstance.globalDic = tmpDic // tmpDict is any value that to be shared among the application
let SocketManager = SocketManagerSingleton();

class SocketManagerSingleton {

}
func someFunction() {        
    var socketManager = SocketManager        
}
func SocketManager() -> SocketManagerSingleton {
    return _SocketManager
}
let _SocketManager = SocketManagerSingleton();

class SocketManagerSingleton {

}
func someFunction() {        
    var socketManager = SocketManager()        
}
class MyClass {

    private static let _sharedInstance = MyClass()

    class func sharedInstance() -> MyClass {
        return _sharedInstance
    }
}
   func init() -> ClassA {
    struct Static {
        static var onceToken : dispatch_once_t = 0
        static var instance : ClassA? = nil
    }

    dispatch_once(&Static.onceToken) {
        Static.instance = ClassA()
    }

    return Static.instance!
}
class MySingleton {

    static let sharedMySingleton = MySingleton()

    private init() {
        // ...
    }
}
class Singleton {
    static let sharedInstance = Singleton()
}
class Singleton {
    static let sharedInstance: Singleton = {
        let instance = Singleton()
        // setup code
        return instance
    }()
}
final class MySingleton {
     private init() {}
     static let shared = MySingleton()
}
let shared = MySingleton.shared
let TEST = Test()

class Test {

    private init() {
        // This is a private (!) constructor
    }
}
class Manager {
    static let sharedInstance = Manager()
    private init() {}
}
public class Singleton {
    private static var sharedInstanceVar = Singleton()

    public class func sharedInstance() -> Singleton {
        return sharedInstanceVar
    }
}


public class SubSingleton: Singleton {

    private static var sharedInstanceToken: dispatch_once_t = 0

    public class override func sharedInstance() -> SubSingleton {
        dispatch_once(&sharedInstanceToken) {
            sharedInstanceVar = SubSingleton()
        }
    return sharedInstanceVar as! SubSingleton
    }
}
class Shared: NSObject {

    static let sharedInstance = Shared()

    private override init() { }
}
protocol Singleton: class {
    static var sharedInstance: Self { get }
}

final class Kraken: Singleton {
    static let sharedInstance = Kraken()
    private init() {}
}
class Singleton {
    static let sharedInstance = Singleton()
}
class Singleton {
    static let sharedInstance: Singleton = {
        let instance = Singleton()
        // setup code
        return instance
    }()
}
struct DataService {

    private static var _instance : DataService?

    private init() {}   //cannot initialise from outer class

    public static var instance : DataService {
        get {
            if _instance == nil {
                DispatchQueue.global().sync(flags: .barrier) {
                    if _instance == nil {
                        _instance = DataService()
                    }
                }
            }
            return _instance!
        }
    }
}
public final class Singleton {    
    private class func sharedInstance() -> Singleton {
        struct Static {
            //Singleton instance.
            static let sharedInstance = Singleton()
        }
        return Static.sharedInstance
    }

    private init() { }

    class var instance: Singleton {
        return sharedInstance()
    }
}
class AppManager {
    private static let _sharedInstance = AppManager()

    class func getSharedInstance() -> AppManager {
       return _sharedInstance
    }

    private init() {} // Privatizing the init method
}

// How to use?
AppManager.getSharedInstance()
class AppManager {
    static let sharedInstance = AppManager()

    private init() {} // Privatizing the init method
}

// How to use?
AppManager.sharedInstance
final class Singleton {
    static let sharedInstance: Singleton = {
        let instance = Singleton()
        // setup code if anything
        return instance
    }()

    private init() {}
}
let signleton = Singleton.sharedInstance
class AppSingleton: NSObject {

    //Shared instance of class
    static let sharedInstance = AppSingleton()

    override init() {
        super.init()
    }
}
static let shared = Self()
class SomeTypeWithASingletonInstance {
   static let shared = Self()
}