日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Swift之深入解析基于闭包的类型擦除

發(fā)布時間:2024/5/21 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Swift之深入解析基于闭包的类型擦除 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
  • 與許多其它語言相比,使 Swift 更加安全,更不易出錯的原因之一是其先進(jìn)的(并且在某種程度上是不容忍的)類型系統(tǒng),這是一種語言功能,有時可能會給人留下深刻的印象,使我們的工作效率提高很多,而有時卻令人沮喪。
  • 在 Swift 中處理泛型時,可能發(fā)生的一種情況,以及通常如何使用基于閉包的類型擦除技術(shù)來解決這種情況。
  • 假設(shè)要編寫一個類,可以通過網(wǎng)絡(luò)加載模型,由于不想為應(yīng)用程序中的每個模型都復(fù)制此類,因此選擇使其成為泛型類,如下所示:
class ModelLoader<T: Unboxable & Requestable> {func load(completionHandler: (Result<T>) -> Void) {networkService.loadData(from: T.requestURL) { data indo {try completionHandler(.success(unbox(data: data)))} catch {let error = ModelLoadingError.unboxingFailed(error)completionHandler(.error(error))}}} }
  • 到目前為止,有了一個 ModelLoader,它能夠加載任何模型(只要它是遵守 Unboxable 協(xié)議的),并且能夠向我們提供 requestURL。但是,我們還希望啟用使用此模型加載器的代碼易于測試,因此將其 API 提取到一個協(xié)議中:
protocol ModelLoading {associatedtype Modelfunc load(completionHandler: (Result<Model>) -> Void) }
  • 這和依賴注入一起能夠輕松地在測試中模擬我們的模型加載 API,但這帶來了一些復(fù)雜性,在每當(dāng)要使用此 API 時,都必須將其稱為協(xié)議 ModelLoading,該協(xié)議具有相關(guān)的類型要求。這意味著僅引用 ModelLoading 是不夠的,因為在沒有更多信息的情況下編譯器無法推斷其關(guān)聯(lián)類型。因此,嘗試執(zhí)行以下操作:
class ViewController: UIViewController {init(modelLoader: ModelLoading) {...} }
  • 會提示如下錯誤:
Protocol 'ModelLoading' can only be used as a generic constraint because it as Self or associated type requirements
  • 但不用擔(dān)心,我們可以通過使用泛型輕松擺脫此錯誤,強制執(zhí)行符合 Modelloading 的具體類型將由 API 用戶指定,并且它將加載期待的模型,像這樣:
class ViewController: UIViewController {init<T: ModelLoading>(modelLoader: T) where T.Model == MyModel {...} }
  • 這是有效的,但由于我們還希望在視圖控制器中引用模型加載程序,需要能夠指定屬性的類型。 T 只在初始化程序的上下文中知道,因此無法定義 T 類型的屬性,除非使視圖控制器類本身成為泛型。相反,讓我們使用類型擦除,能夠保存某種 T 的引用,而無需實際使用其類型,這可以通過創(chuàng)建擦除類型的類,例如“包裝類”來完成:
class AnyModelLoader<T>: ModelLoading {typealias CompletionHandler = (Result<T>) -> Voidprivate let loadingClosure: (CompletionHandler) -> Voidinit<L: ModelLoading>(loader: L) where L.Model == T {loadingClosure = loader.load}func load(completionHandler: CompletionHandler) {loadingClosure(completionHandler)} }
  • 以上這種類型擦除技術(shù),其實在 Swift 標(biāo)準(zhǔn)庫中也很常用,例如在 AnySequence 類型中。基本上,將關(guān)聯(lián)值要求的協(xié)議包裝為泛型類型,然后可以直接使用它而無需使使用它的類也是泛型的。現(xiàn)在可以更新之前的 ViewController,使用 AnyModelloader:
class ViewController: UIViewController {private let modelLoader: AnyModelLoader<MyModel>init<T: ModelLoading>(modelLoader: T) where T.Model == MyModel {self.modelLoader = AnyModelLoader(loader: modelLoader)super.init(nibName: nil, bundle: nil)} }
  • 至此,我們現(xiàn)在擁有一個面向協(xié)議的 API,具有易于 Mock 的特性,且仍然可以在普通類中使用,這歸功于類型擦除。上述技術(shù)實際上很好,但它確實涉及額外的步驟,為代碼增加了一些復(fù)雜化。但是,事實證明,我們實際上可以直接在視圖控制器中進(jìn)行基于閉合的類型擦除 ,而不是必須通過 AnyModelloader 類。然后視圖控制器將如下所示:
class ViewController: UIViewController {private let loadModel: ((Result<MyModel>) -> Void) -> Voidinit<T: ModelLoading>(modelLoader: T) where T.Model == MyModel {loadModel = modelLoader.loadsuper.init(nibName: nil, bundle: nil)} }
  • 與類型擦除類 AnyModelloader 一樣,可以參考 load 函數(shù)作為閉包的實現(xiàn),并只需在視圖控制器中保存引用。現(xiàn)在,每當(dāng)我們想要加載模型時,只需調(diào)用 loadmodel,就像任何其他函數(shù)或閉包一樣:
override func viewWillAppear(_ animated: Bool) {super.viewWillAppear(animated)loadModel { result inswitch result {case .success(let model):render(model)case .error(let error):render(error)}} }

總結(jié)

以上是生活随笔為你收集整理的Swift之深入解析基于闭包的类型擦除的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。