深入理解Swift中单例模式的替换及Swift 3.0单例模式的实现

2020-01-08 23:52:00王冬梅

上面代码中的依赖关系明显比之前更为清晰,而且也更方便后期维护和编写测试实例。另外,通过 LogOutService 对象我们将某些特定服务抽离了出来,避免了单例中常见的臃肿状态。

协议化改造

将一个单例滥用的应用一次性全面改写为上面那样的依赖注入和服务化显然是一件非常耗时且不合理的事情。所以下面将会介绍通过协议对单例进行逐步改造的方法,这里主要的做法就是将上面 LogOutService 提供的服务改写为协议:


protocol LogOutService {
 func logOut()
}

protocol NetworkService {
 func request(_ endpoint: Endpoint, completionHandler: @escaping () -> Void)
}

protocol NavigationService {
 func showLoginScreen()
 func showProfile(for user: User)
 ...
}

定义好协议服务之后,我们让原有的单例遵循该协议。此时我们可以在不修改原有代码实现的同时将单例对象当作服务进行依赖注入。


extension UserManager: LoginService, LogOutService {}

extension AppDelegate: NavigationService {
 func showLoginScreen() {
 navigationController.viewControllers = [
 LoginViewController(
 loginService: UserManager.shared,
 navigationService: self
 )
 ]
 }

 func showProfile(for user: User) {
 let viewController = ProfileViewController(
 user: user,
 logOutService: UserManager.shared
 )

 navigationController.pushViewController(viewController, animated: true)
 }
}

Swift3.0 单例模式实现的几种方法-Dispatch_Once

在开发中需要使用单例模式是再寻常不过的了,正常我们的思路是使用GCD的dispatch_once这个API来写,然而在swift/274756.html">swift3.0中,苹果已经废弃了这个方法,不过不用担心,我们可以用别的方式来实现。

结合swift语言的特性,总结了以下几种写法:

普通创建法 静态创建法 struct创建法 通过给DIspatchQueue添加扩展实现

注意:这里我希望大家除了使用还要会调用该对应的方法

1.普通创建法


//MARK - : 单例:方法1
 static let shareSingleOne = Single()

2.静态创建法


let single = Single()
class Single: NSObject {
 //-MARK: 单例:方法2
 class var sharedInstance2 : Single {
  return single
 }
}

3.struct创建法


 //-MARK: 单例:方法3
 static var shareInstance3:Single{
 struct MyStatic{
  static var instance :Single = Single()
 }
 return MyStatic.instance;
 }

4.通过给DispatchQueue添加扩展实现


public extension DispatchQueue { 
 
 private static var _onceTracker = [String]() 
 
 /** 
 Executes a block of code, associated with a unique token, only once. The code is thread safe and will 
 only execute the code once even in the presence of multithreaded calls. 
 
 - parameter token: A unique reverse DNS style name such as com.vectorform.<name> or a GUID 
 - parameter block: Block to execute once 
 */ 
 public class func once(token: String, block:()->Void) { 
 objc_sync_enter(self) 
 defer { objc_sync_exit(self) } 
 
 if _onceTracker.contains(token) { 
  return 
 } 
 
 _onceTracker.append(token) 
 block() 
 } 
}