成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Swift 基于閉包的類型擦除

開發(fā) 前端
今天,我想重點介紹在 Swift 中處理泛型時可能發(fā)生的一種情況,以及我通常如何使用基于閉包的類型擦除技術(shù)來解決這種情況。

[[407967]]

與許多其他語言相比,使Swift更加安全,更不易出錯的原因之一是其先進的(并且在某種程度上是不容忍的)類型系統(tǒng)。這是一種語言功能,有時可能會給人留下深刻的印象,使您的工作效率提高很多,而有時卻令人沮喪。

今天,我想重點介紹在 Swift 中處理泛型時可能發(fā)生的一種情況,以及我通常如何使用基于閉包的類型擦除技術(shù)來解決這種情況。

假設(shè)我們要編寫一個類,使我們可以通過網(wǎng)絡(luò)加載模型。由于我們不想為應(yīng)用程序中的每個模型都復(fù)制此類,因此我們選擇使其成為泛型類,如下所示:

  1. class ModelLoader<T: Unboxable & Requestable> { 
  2.     func load(completionHandler: (Result<T>) -> Void) { 
  3.         networkService.loadData(from: T.requestURL) { data in 
  4.             do { 
  5.                 try completionHandler(.success(unbox(data: data))) 
  6.             } catch { 
  7.                 let error = ModelLoadingError.unboxingFailed(error) 
  8.                 completionHandler(.error(error)) 
  9.             } 
  10.         } 
  11.     } 

到目前為止,我們現(xiàn)在有了一個 ModelLoader,它能夠加載任何模型(只要它是遵守 Unboxable 協(xié)議的),并且能夠向我們提供requestURL。但是,我們還希望啟用使用此模型加載器的代碼易于測試,因此我們將其API提取到一個協(xié)議中:

  1. protocol ModelLoading { 
  2.     associatedtype Model 
  3.  
  4.     func load(completionHandler: (Result<Model>) -> Void) 

這和依賴注入一起使我們能夠輕松地在測試中模擬我們的模型加載API。但這帶來了一些復(fù)雜性——在每當(dāng)我們要使用此API時,我們現(xiàn)在都必須將其稱為協(xié)議 ModelLoading,該協(xié)議具有相關(guān)的類型要求。這意味著僅引用 ModelLoading 是不夠的,因為在沒有更多信息的情況下編譯器無法推斷其關(guān)聯(lián)類型。因此,嘗試執(zhí)行以下操作:

  1. class ViewController: UIViewController { 
  2.     init(modelLoader: ModelLoading) { 
  3.         ... 
  4.     } 

會給我們這個錯誤:

  1. Protocol 'ModelLoading' can only be used as a generic constraint because it as Self or associated type requirements 

但不用擔(dān)心,我們可以通過使用泛型輕松擺脫此錯誤,強制執(zhí)行符合 Modelloading 的具體類型將由API用戶指定,并且它將加載我們期待的模型。像這樣:

  1. class ViewController: UIViewController { 
  2.     init<T: ModelLoading>(modelLoader: T) where T.Model == MyModel { 
  3.         ... 
  4.     } 

這是有效的,但由于我們還希望在我們的視圖控制器中引用我們的模型加載程序,我們需要能夠指定屬性的類型。 T 只在我們的初始化程序的上下文中知道,因此我們無法定義T類型的屬性,除非我們使視圖控制器類本身成為泛型 - 這將非常迅速使我們進一步陷入到處都是通用課程的兔子洞中(down into a rabit hole 出自愛麗絲夢游記,意只簡單的事情變得越來來復(fù)雜和荒謬)。

相反,讓我們使用類型擦除,使我們能夠保存某種 T 的引用,而無需實際使用其類型。這可以通過創(chuàng)建擦除類型的類,例如 包裝類 來完成:

  1. class AnyModelLoader<T>: ModelLoading { 
  2.     typealias CompletionHandler = (Result<T>) -> Void 
  3.  
  4.     private let loadingClosure: (CompletionHandler) -> Void 
  5.  
  6.     init<L: ModelLoading>(loader: L) where L.Model == T { 
  7.         loadingClosure = loader.load 
  8.     } 
  9.  
  10.     func load(completionHandler: CompletionHandler) { 
  11.         loadingClosure(completionHandler) 
  12.     } 

以上這種類型擦除技術(shù),其實在 Swift 標(biāo)準(zhǔn)庫中也很常用,例如在 AnySequence 類型中。基本上,您將關(guān)聯(lián)值要求的協(xié)議包裝為泛型類型,然后您可以直接使用它而無需使使用它的類也是泛型的。

我們現(xiàn)在可以更新我們之前的 ViewController,使用 AnyModelloader:

  1. class ViewController: UIViewController { 
  2.     private let modelLoader: AnyModelLoader<MyModel> 
  3.  
  4.     init<T: ModelLoading>(modelLoader: T) where T.Model == MyModel { 
  5.         self.modelLoader = AnyModelLoader(loader: modelLoader) 
  6.         super.init(nibName: nil, bundle: nil) 
  7.     } 

好了!我們現(xiàn)在擁有一個面向協(xié)議的API,具有易于Mock的特性,且仍然可以在普通類中使用,這歸功于類型擦除。

現(xiàn)在,獎勵時間的時間。上述技術(shù)實際上很好,但它確實涉及一個額外的步驟,為我們的代碼增加了一些復(fù)雜化。但是,事實證明,我們實際上可以直接在我們的視圖控制器中進行基于閉合的類型擦除 ——而不是必須通過 AnyModelloader 類。然后,我們的視圖控制器將如下所示:

  1. class ViewController: UIViewController { 
  2.     private let loadModel: ((Result<MyModel>) -> Void) -> Void 
  3.  
  4.     init<T: ModelLoading>(modelLoader: T) where T.Model == MyModel { 
  5.         loadModel = modelLoader.load 
  6.         super.init(nibName: nil, bundle: nil) 
  7.     } 

與我們的類型擦除類 AnyModelloader 一樣,我們可以參考 load 函數(shù)作為閉包的實現(xiàn),并只需在我們的視圖控制器中保存引用。現(xiàn)在,每當(dāng)我們想要加載模型時,我們只需調(diào)用 loadmodel,就像我們的任何其他函數(shù)或閉包一樣:

  1. override func viewWillAppear(_ animated: Bool) { 
  2.     super.viewWillAppear(animated) 
  3.  
  4.     loadModel { result in 
  5.         switch result { 
  6.         case .success(let model): 
  7.             render(model) 
  8.         case .error(let error): 
  9.             render(error) 
  10.         } 
  11.     } 

就是這樣!希望在處理Swift代碼中的泛型和協(xié)議時,您可以找到上述技術(shù)。

本文轉(zhuǎn)載自微信公眾號「 Swift社區(qū)」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系 Swift社區(qū)公眾號。

 

責(zé)任編輯:姜華 來源: Swift社區(qū)
相關(guān)推薦

2022-03-31 09:01:10

Swift類型擦除類型安全性

2024-01-22 09:51:32

Swift閉包表達式尾隨閉包

2009-07-22 07:43:00

Scala閉包

2021-02-21 16:21:19

JavaScript閉包前端

2016-09-14 09:20:05

JavaScript閉包Web

2009-07-24 17:30:37

Javascript閉

2023-11-02 08:53:26

閉包Python

2020-09-18 14:12:28

閉包Rsut函數(shù)

2012-11-29 10:09:23

Javascript閉包

2010-06-23 10:24:42

Javascript閉

2016-11-01 09:18:33

Python閉包

2016-09-18 20:53:16

JavaScript閉包前端

2020-10-14 15:15:28

JavaScript(

2011-05-25 14:48:33

Javascript閉包

2013-05-02 09:44:57

PHP閉包

2016-10-27 19:26:47

Javascript閉包

2019-11-07 21:51:18

閉包前端函數(shù)

2014-06-06 09:13:28

SwiftSwift編程

2025-05-30 02:31:00

2009-11-23 14:17:50

PHP 5.3閉包語法
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 欧美aa在线 | 久久91av | 国产亚洲精品综合一区 | 午夜精品在线 | 国产精品久久久久一区二区三区 | 日韩成人在线视频 | 国产传媒毛片精品视频第一次 | 偷牌自拍| 欧美精品久久久 | 九九精品在线 | 亚洲成人一区 | 一区二区三区视频在线观看 | 最新免费av网站 | www国产精品 | 欧美中文字幕在线 | 欧美日韩福利视频 | 91精品国产综合久久久久蜜臀 | av国产在线观看 | 国产一区2区 | 国产高清精品在线 | 久久久久国产一区二区三区 | 久久9精品 | 久久久久久久久久久久亚洲 | 男人阁久久 | 日本人做爰大片免费观看一老师 | 亚洲一级毛片 | 99久久成人| 一区二区电影网 | 中文字幕 亚洲一区 | www日本在线播放 | 免费视频一区二区三区在线观看 | 成人三级影院 | 久夜精品 | 四虎影院免费在线 | 日本a v在线播放 | 亚洲高清视频一区二区 | 美女一级黄 | 中文字幕在线视频网站 | 一区二区三区久久 | 成人一区二区三区视频 | 久久久69|