如何使用单例模式

可以看下这个图:

如何使用单例模式 - 图1

这是一个日志类,有一个属性 (是一个单例对象) 和两个方法 (sharedInstance()init())。

第一次调用 sharedInstance() 的时候,instance 属性还没有初始化。所以我们要创建一个新实例并且返回。

下一次你再调用 sharedInstance() 的时候,instance 已经初始化完成,直接返回即可。这个逻辑确保了这个类只存在一个实例对象。

接下来我们继续完善单例模式,通过这个类来管理专辑数据。

注意到在我们前面的截图里,分组中有个 API 分组,这里可以放那些提供后台服务的类。在这个分组中创建一个新的文件 LibraryAPI.swift ,继承自 NSObject 类。

LibraryAPI 里添加下面这段代码:

  1. //1
  2. class var sharedInstance: LibraryAPI {
  3. //2
  4. struct Singleton {
  5. //3
  6. static let instance = LibraryAPI()
  7. }
  8. //4
  9. return Singleton.instance
  10. }

在这几行代码里,做了如下工作:

创建一个计算类型的类变量,这个类变量,就像是 objc 中的静态方法一样,可以直接通过类访问而不用实例对象。具体可参见苹果官方文档的 属性 这一章。

在类变量里嵌套一个 Singleton 结构体。

Singleton 封装了一个静态的常量,通过 static 定义意味着这个属性只存在一个,注意 Swift 中 static 的变量是延时加载的,意味着 Instance 直到需要的时候才会被创建。

同时再注意一下,因为它是一个常量,所以一旦创建之后不会再创建第二次。这些就是单例模式的核心所在:一旦初始化完成,当前类存在一个实例对象,初始化方法就不会再被调用。

返回计算后的属性值。

注意:更多的单例模式实例可以看看 Github 上的这个示例,列举了单例模式的若干种实现方式。

你现在可以将这个单例作为专辑管理类的入口,接下来我们继续创建一个处理专辑数据持久化的类。

新建 PersistencyManager.swift 并添加如下代码:

  1. private var albums = [Album]()

在这里我们定义了一个私有属性,用来存储专辑数据。这是一个可变数组,所以你可以很容易的增加或者删除数据。

然后加上一些初始化的数据:

  1. override init() {
  2. //Dummy list of albums
  3. let album1 = Album(title: "Best of Bowie",
  4. artist: "David Bowie",
  5. genre: "Pop",
  6. coverUrl: "http://img3.douban.com/mpic/s1497881.jpg",
  7. year: "1992")
  8. let album2 = Album(title: "It's My Life",
  9. artist: "No Doubt",
  10. genre: "Pop",
  11. coverUrl: "http://img3.doubanio.com/mpic/s3880529.jpg",
  12. year: "2003")
  13. let album3 = Album(title: "Nothing Like The Sun",
  14. artist: "Sting",
  15. genre: "Pop",
  16. coverUrl: "http://img3.doubanio.com/mpic/s3708339.jpg",
  17. year: "1999")
  18. let album4 = Album(title: "Staring at the Sun",
  19. artist: "U2",
  20. genre: "Pop",
  21. coverUrl: "http://img3.douban.com/mpic/s1882422.jpg",
  22. year: "2000")
  23. let album5 = Album(title: "American Pie",
  24. artist: "Madonna",
  25. genre: "Pop",
  26. coverUrl: "http://img3.douban.com/mpic/s3105351.jpg",
  27. year: "2000")
  28. albums = [album1, album2, album3, album4, album5]
  29. }

在这个初始化方法里,我们初始化了五张专辑。如果上面的专辑没有你喜欢的,你可以随意替换成你的菜:]

然后添加如下方法:

  1. func getAlbums() -> [Album] {
  2. return albums
  3. }
  4. func addAlbum(album: Album, index: Int) {
  5. if (albums.count >= index) {
  6. albums.insert(album, atIndex: index)
  7. } else {
  8. albums.append(album)
  9. }
  10. }
  11. func deleteAlbumAtIndex(index: Int) {
  12. albums.removeAtIndex(index)
  13. }

这些方法可以让你自由的访问、添加、删除专辑数据。

这时你可以运行一下你的项目,确保编译通过以便进行下一步操作。

此时你或许会感到好奇: PersistencyManager 好像不是单例啊?是的,它确实不是单例。不过没关系,在接下来的外观模式章节,你会看到 LibraryAPIPersistencyManagerx 之间的联系。

完成到这一步的Demo: