搜索
您的当前位置:首页正文

单例在Swift中的正确实现方式

来源:二三娱乐

单例三要素

  • 唯一性:在一个应用程序的生命周期中,只有一个实例存在。单例提供了一个唯一的全局状态,例如:NSNotification,UIApplication和NSUserDefaults
  • 构造器私有:为了保证单例的唯一性,构造器必须私有,防止其他对象也能创建出单例类的实例
  • 线程安全:确保单例在整个应用程序的生命周期中是唯一的,防止两个线程在同一时间初始化同一个单例,这样就有潜在的风险得到两个不同的单例。使用GCD的dispatch_once来确保初始化单例的代码在运行时只执行一次

OC

+ (instancetype)sharedDataCenter {
    static KCDataCenter *dataCenter = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        dataCenter = [[KCDataCenter alloc] init];
    });
    return dataCenter;
}

Swift

最优雅的写法

如果你深谙单例三要素,相信这种写法你很容易接收

class KCDataCenter {
    static let sharedDataCenter = KCDataCenter()
    private init() {}
}

演变过程

照搬OC写法
class KCDataCenter {
    class var sharedDataCenter: KCDataCenter {
        struct Static {
            static var onceToken : dispatch_once_t = 0
            static var dataCenter : KCDataCenter? = nil
        }
        dispatch_once(&Static.onceToken) {
            static.dataCenter = KCDataCenter()
        }
        return Static.dataCenter!
    }
}
结构体写法
class KCDataCenter {
    class var sharedDataCenter : KCDataCenter {
        struct Static {
            static let dataCenter = KCDataCenter()
        }
        return Static.dataCenter
    }
}
全局变量写法

中文校对版中这里有一处错误,详解请看原文

private let dataCenter = KCDataCenter()
class KCDataCenter {
    class var sharedDataCenter : KCDataCenter {
        return dataCenter
    }
}

private保证线程安全

“全局变量(静态成员变量和结构体以及枚举)的延迟构造器在其被第一次访问时会加载,并以dispatch_once的方式启动来确保初始化的原子性。这让你写代码时可以用一种很酷的方式来使用dispatch_once:直接用一个全局变量的构造器去做初始化并用private来修饰。“ — Apple’s Swift Blog

接下来就是最优雅的写法
class KCDataCenter {
    static let sharedDataCenter = KCDataCenter()
    private init() {}
}
Top