最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入理解Swift中單例模式的替換及Swift 3.0單例模式的實(shí)現(xiàn)

 更新時間:2017年11月07日 11:19:41   作者:BigNerdCoding  
這篇文章主要給大家介紹了關(guān)于Swift中單例模式替換的相關(guān)資料,然后又跟大家分享了關(guān)于Swift3.0 單例模式實(shí)現(xiàn)的幾種方法-Dispatch_Once的內(nèi)容,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來一起看看吧。

前言

除了 MVC、MVVM 之外,單例模式可以說是 iOS 開發(fā)中另一常見的設(shè)計(jì)模式。無論是 UIKit 或是一些流行的三方庫,我們都能看到單例的身影。而我們開發(fā)者本身也會潛意識地將這些類庫中的代碼當(dāng)作最佳實(shí)踐并將其帶入日常工作中,哪怕很多人都知道單例存在一些明顯的缺陷。

針對單例的缺陷,本文將介紹一些替換或改造單例模式的方法來提升代碼質(zhì)量。

單例的優(yōu)點(diǎn)

除了上面提到的模仿最佳實(shí)踐之外,單例的流行肯定也有內(nèi)在的原因和理由。例如:單例對象保證了只有一個實(shí)例的存在,這樣有利于我們協(xié)調(diào)系統(tǒng)整體的行為。比如在某個服務(wù)器程序中,該服務(wù)器的配置信息存放在一個文件中,這些配置數(shù)據(jù)由一個單例對象統(tǒng)一讀取,然后服務(wù)進(jìn)程中的其他對象再通過這個單例對象獲取這些配置信息。這種方式簡化了在復(fù)雜環(huán)境下的配置管理。 另一方面,全局單一對象也減少了不必要的對象創(chuàng)建和銷毀動作提高了效率。

下面是一個典型的單例模式代碼:

class UserManager {
 static let shared = UserManager()
 
 private init() {
 // 單例模式,防止出現(xiàn)多個實(shí)例
 }
 
 ....
}

extension UserManager {
 func logOut( ) {
 ...
 }
 
 func logIn( ) {
 ...
 }
}

class ProfileViewController: UIViewController {
 private lazy var nameLabel = UILabel()

 override func viewDidLoad() {
 super.viewDidLoad()
 nameLabel.text = UserManager.shared.currentUser?.name
 }

 private func handleLogOutButtonTap() {
 UserManager.shared.logOut()
 }
}

單例的缺陷

雖然上面提到了單例的一些優(yōu)點(diǎn),但是這不能掩蓋單例模式一些明顯的缺陷:

  • 全局共享可修改的狀態(tài):單例模式的副作用之一就是那些共享狀態(tài)量在 app 的生命周期內(nèi)都可能發(fā)生修改,而這些修改可能造成一些位置錯誤。更為糟糕的是因?yàn)樽饔糜蚝蜕芷诘奶匦?,這些問題還非常難定位。
  • 依賴關(guān)系不明確:因?yàn)閱卫谌侄挤浅H菀走M(jìn)行訪問,這將是我們的代碼變成所謂的 意大利面條 式的代碼。單例與使用者的關(guān)系界限不明確,后期維護(hù)也非常麻煩。
  • 難以追蹤測試:因?yàn)閱卫J脚c app 擁有同樣的生命周期而生命周期內(nèi)進(jìn)行的任意修改,所以無法確保一個干凈的實(shí)例用于測試。
  • 由于單利模式中沒有抽象層,因此單例類的擴(kuò)展有很大的困難。
  • 單例類的職責(zé)過重,在一定程度上違背了 “單一職責(zé)原則”。

依賴注入

與之間之間使用單例對象不同,這里我們可以在初始化是進(jìn)行依賴注入。

class ProfileViewController: UIViewController {
 private let user: User
 private let logOutService: LogOutService
 private lazy var nameLabel = UILabel()

 init(user: User, logOutService: LogOutService) {
 self.user = user
 self.logOutService = logOutService
 super.init(nibName: nil, bundle: nil)
 }

 override func viewDidLoad() {
 super.viewDidLoad()
 nameLabel.text = user.name
 }

 private func handleLogOutButtonTap() {
 logOutService.logOut()
 }
}

class LogOutService {
 private let user: User
 private let networkService: NetworkService
 private let navigationService: NavigationService

 init(user: User,
 networkService: NetworkService,
 navigationService: NavigationService) {
 self.user = user
 self.networkService = networkService
 self.navigationService = navigationService
 }

 func logOut() {
 networkService.request(.logout(user)) { [weak self] in
 self?.navigationService.showLoginScreen()
 }
 }
}

上面代碼中的依賴關(guān)系明顯比之前更為清晰,而且也更方便后期維護(hù)和編寫測試實(shí)例。另外,通過 LogOutService 對象我們將某些特定服務(wù)抽離了出來,避免了單例中常見的臃腫狀態(tài)。

協(xié)議化改造

將一個單例濫用的應(yīng)用一次性全面改寫為上面那樣的依賴注入和服務(wù)化顯然是一件非常耗時且不合理的事情。所以下面將會介紹通過協(xié)議對單例進(jìn)行逐步改造的方法,這里主要的做法就是將上面 LogOutService 提供的服務(wù)改寫為協(xié)議:

protocol LogOutService {
 func logOut()
}

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

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

定義好協(xié)議服務(wù)之后,我們讓原有的單例遵循該協(xié)議。此時我們可以在不修改原有代碼實(shí)現(xiàn)的同時將單例對象當(dāng)作服務(wù)進(jìn)行依賴注入。

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 單例模式實(shí)現(xiàn)的幾種方法-Dispatch_Once

在開發(fā)中需要使用單例模式是再尋常不過的了,正常我們的思路是使用GCD的dispatch_once這個API來寫,然而在swift3.0中,蘋果已經(jīng)廢棄了這個方法,不過不用擔(dān)心,我們可以用別的方式來實(shí)現(xiàn)。

結(jié)合swift語言的特性,總結(jié)了以下幾種寫法:

  • 普通創(chuàng)建法
  • 靜態(tài)創(chuàng)建法
  • struct創(chuàng)建法
  • 通過給DIspatchQueue添加擴(kuò)展實(shí)現(xiàn)

注意:這里我希望大家除了使用還要會調(diào)用該對應(yīng)的方法

1.普通創(chuàng)建法

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

2.靜態(tài)創(chuàng)建法

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

3.struct創(chuàng)建法

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

4.通過給DispatchQueue添加擴(kuò)展實(shí)現(xiàn)

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() 
 } 
} 

使用字符串token作為once的ID,執(zhí)行once的時候加了一個鎖,避免多線程下的token判斷不準(zhǔn)確的問題。

使用的時候可以傳token

DispatchQueue.once(token: "com.vectorform.test") { 
 print( "Do This Once!" ) 
} 

或者使用UUID也可以:

private let _onceToken = NSUUID().uuidString 
 
DispatchQueue.once(token: _onceToken) { 
 print( "Do This Once!" ) 
} 

結(jié)語

單例模式并不是毫無可取之處,例如在日志服務(wù)、外設(shè)管理等場景下還是非常適用的。但是大多數(shù)時候單例模式由于依賴關(guān)系不明確以及全局共享可變狀態(tài)可能會增加系統(tǒng)的復(fù)雜度造成一系列未知問題。如果你當(dāng)前的代碼中使用了大量的單例模式的話,我希望本文能夠幫你從中解脫出來構(gòu)建一個更健壯的系統(tǒng)。

好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • Swift學(xué)習(xí)教程之SQLite的基礎(chǔ)使用

    Swift學(xué)習(xí)教程之SQLite的基礎(chǔ)使用

    這篇文章主要給大家介紹了關(guān)于Swift學(xué)習(xí)教程之SQLite的基礎(chǔ)使用,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Swift SQLite具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • swift中正確安全聲明一個單例的方法實(shí)例

    swift中正確安全聲明一個單例的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于swift中如何正確安全聲明一個單例的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • swift中defer幾個簡單的使用場景詳解

    swift中defer幾個簡單的使用場景詳解

    在Swift 2.0中,Apple提供了defer關(guān)鍵字,讓我們可以實(shí)現(xiàn)同樣的效果,這篇文章主要介紹了關(guān)于swift中defer幾個簡單的使用場景的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用defer具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧。
    2018-03-03
  • Swift 3.1聊天界面鍵盤效果的實(shí)現(xiàn)詳解

    Swift 3.1聊天界面鍵盤效果的實(shí)現(xiàn)詳解

    這篇文章主要給大家介紹了Swift 3.1聊天界面鍵盤效果實(shí)現(xiàn)的相關(guān)資料,文中介紹的非常詳細(xì),相信對大家的學(xué)習(xí)或者工作具有一定的參考價值,需要的朋友們下面來一起看看吧。
    2017-04-04
  • 淺談在Swift中關(guān)于函數(shù)指針的實(shí)現(xiàn)

    淺談在Swift中關(guān)于函數(shù)指針的實(shí)現(xiàn)

    這篇文章主要介紹了淺談在Swift中關(guān)于函數(shù)指針的實(shí)現(xiàn),是作者根據(jù)C語言的指針特性在Swifft中做出的一個實(shí)驗(yàn),需要的朋友可以參考下
    2015-07-07
  • Swift中如何避免循環(huán)引用的方法

    Swift中如何避免循環(huán)引用的方法

    本篇文章主要介紹了Swift中如何避免循環(huán)引用的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • swift中獲取字符串前綴的七種方法總結(jié)

    swift中獲取字符串前綴的七種方法總結(jié)

    在日常的開發(fā)中,經(jīng)常會需要獲取一個字符串的前綴,在這篇文章中我總結(jié)了在 Swift 中檢查字符串前綴的多種方法分享給大家,看看有沒有你不知道的
    2023-12-12
  • Swift中轉(zhuǎn)義閉包示例詳解

    Swift中轉(zhuǎn)義閉包示例詳解

    在Swift 中的閉包類似于結(jié)構(gòu)塊,并可以在任何地方調(diào)用,下面這篇文章主要給大家介紹了關(guān)于Swift中轉(zhuǎn)義閉包的相關(guān)資料,需要的朋友可以參考下
    2021-11-11
  • 淺析Swift中struct與class的區(qū)別(匯編角度底層分析)

    淺析Swift中struct與class的區(qū)別(匯編角度底層分析)

    這篇文章主要介紹了Swift中struct與class的區(qū)別 ,本文從匯編角度分析struct與class的區(qū)別,通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-03-03
  • 如何快速用上Swift靜態(tài)庫詳解

    如何快速用上Swift靜態(tài)庫詳解

    這篇文章主要給大家介紹了關(guān)于如何快速用上Swift靜態(tài)庫的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-03-03

最新評論

湖南省| 汝阳县| 临西县| 瑞昌市| 商丘市| 辽阳县| 紫阳县| 武威市| 阿拉善左旗| 介休市| 永靖县| 古蔺县| 公主岭市| 临夏县| 宕昌县| 宜黄县| 西和县| 盱眙县| 沾化县| 昭觉县| 盘山县| 永丰县| 贵州省| 泽库县| 齐齐哈尔市| 湖南省| 蒙阴县| 南木林县| 纳雍县| 桂林市| 临高县| 通化县| 白沙| 怀宁县| 冀州市| 海安县| 集贤县| 门源| 班玛县| 洛隆县| 乌兰浩特市|