什么是单例及如何在swift中使用单例

原文地址: 点击打开链接

最近抽风 粗略撸了几天的swift基础资料,  新项目就用swift写的.基本上是解决一个问题又碰到一个问题. 走到哪儿卡到哪儿
关于单例OC没什么好说的 .  度娘搜了下swift的单例,无外乎抄来抄去.  当然讲的讲的也挺好.  这里搜到一遍最新swift的资料 ,  大家看一下 .  希望我有时间 翻一下.


单例是啥以及如何在swift中使用单例

软件开发中单例使用的非常广泛.尽管它很流行,一般还是反对使用它.  为啥呢? 在这个文章中,我将解释什么事单例以及如何使用

文章支持到Swift4 , Xcode9

什么是单例

单例很好理解.单例模式就是保证类的实例对象只有一个. 很简单,对吧?

  单例要保证实例对象只有一个

如果你用过苹果的框架,那你肯定有可能已经用到单例了.看看下面的栗子,是不是很熟悉

// Shared URL Session
let sharedURLSession = URLSession.shared

// Default File Manager
let defaultFileManager = FileManager.default

// Standard User Defaults
let standardUserDefaults = UserDefaults.standard

// Default Payment Queue
let defaultPaymentQueue = SKPaymentQueue.default()
单例模式非常有用,你肯定有过多次想要确定某个类只实例化了一次,而且你用到的就是那个对象. 恰好这就是单例最基本且唯一的目标.


Storekit framework 的默认支付队列就是一个很好的栗子. 应用程序永远都不应该创建 SKPaymentQueue 这个类的实例. 操作系统使用 StoreKit框架创建一个支付队列供你的APP使用.这个支付队列可以通过 SKPaymentQueue 这个类的 default() 方法获取到. 这真是单例模式的一个完美举例

全局获取

但是单例有一个副作用也是我们经常选择使用单例的原因: 全局获取  (全局获取 某一个对象)

不过对单例而言 全局访问单例对象不过是单例模式的一点点副作用罢了.

不幸的是,很多开发人员在工程里面很随意的通过单例获取对象,(不是说的我吧?哭).  默认的支付队列可以通过 default() 获取.这就意味着 你可以在项目的任何地方或者这个队列.确实很方便,不过是要付出代价的

如果你想知道关于更过的单利模式的缺点,我建议你读一下这篇文章单利怎么坏了就 这篇文章有详细的说明 (没有翻译)


swift中如何使用单例

这里我将展示两个方法介绍如何在swift中使用单例.  第一个方法就不要用了,  我只是想用它说明一下swift语法的概念.

全局变量

最简单的创建单例的方法就是创建一个 全局变量

let sharedNetworkManager = NetworkManager(baseURL: API.baseURL)

class NetworkManager {

    // MARK: - Properties

    let baseURL: URL

    // Initialization

    init(baseURL: URL) {
        self.baseURL = baseURL
    }

}
通过在全局变量命名区创建一个变量, 整个项目的任何对象下 都可以获取这个单例对象了.举个例子 ,我们可以再AppDelegate中调用

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    print(sharedNetworkManager)
    return true
}
在swift中全局变量都是懒加载实现的,  也就是说 只有第一次调用时,才会被引用.
swift 初始化有一个附加的好处就是自带dispath_once 的方法.这就保证了初始化方法只调用一次. 对你想要的单例模式而言这是很重要的

使用全局命名空间也有很多缺点.最大的缺点就是命名空间 太凌乱了.另外一个缺点就是NetWorkManager的初始化方法不能够被私有化,这个这个类就有可能在很多地方被实例化.我介绍一个更好的,也是我更喜欢的在swift中使用的方法.

Static Property and Private Initializer

swift 2 有了静态成员和权限访问设置. 这就有了更多的创建单利的方法. 比使用全局变量更简洁 更优雅.  话不多说看栗子

class NetworkManager {

    // MARK: - Properties

    static let shared = NetworkManager(baseURL: API.baseURL)

    // MARK: -

    let baseURL: URL

    // Initialization

    private init(baseURL: URL) {
        self.baseURL = baseURL
    }

}

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    print(NetworkManager.shared)
    return true
}
好几个实现的细节有所变化.首先init方法私有化,只有类自己内部才能创建自己的实例. 这是最明显的一个好处

其次, 我们声明了 shared 这个静态常量.这个属性给其他类一个访问NetworkManager的通道.

这就没有必要再给静态属性添加 lazy 关键字. 还记得前面说的 全局变量和静态成员默认都是懒加载的,这是另外一个好处

接下来的这个例子就有一点复杂了.主要区别就是单例在闭包中初始化.这样允许初始化的时候配置更多的东西.

class NetworkManager {

    // MARK: - Properties

    private static var sharedNetworkManager: NetworkManager = {
        let networkManager = NetworkManager(baseURL: API.baseURL)

        // Configuration
        // ...

        return networkManager
    }()

    // MARK: -

    let baseURL: URL

    // Initialization

    private init(baseURL: URL) {
        self.baseURL = baseURL
    }

    // MARK: - Accessors

    class func shared() -> NetworkManager {
        return sharedNetworkManager
    }

}
私有声明这个属性,单例通过shared方法访问.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    print(NetworkManager.shared())
    return true
}

cocoa里面的单例

通过上面的几个实现方法,我们已经模仿了cocoa 在swift3 中采用的好几个实现单例的方法.

// Shared URL Session
let sharedURLSession = URLSession.shared

// Default File Manager
let defaultFileManager = FileManager.default

// Standard User Defaults
let standardUserDefaults = UserDefaults.standard

// Default Payment Queue
let defaultPaymentQueue = SKPaymentQueue.default()

单例有毛病吗

在本篇的别处,我说了单例在项目中可能会有什么问题.我的建议就是能不用就不用.打算使用单例的时候,退一步看看有没有其他办法,是不是就必须要用单例?

尽管单例没有直接的自身问题.大多数开发者还是因为错误的原因采用它.因为方便啊,单例在任何地方都可以访问.









猜你喜欢

转载自blog.csdn.net/iosyangming/article/details/78923777