国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

聊聊Swift 中 key paths 的能力

開發(fā) 前端
Swift 不斷獲取越來越多的更具動態(tài)性的功能,同時還一直把它的關注點放在代碼的類型安全上。其中的一個特性就是 KeyPath。

[[409895]]

前言

自從 swift 剛開始就被設計為是編譯時安全和靜態(tài)類型后,它就缺少了那種我么經常在運行時語言中的動態(tài)特性,比如 Object-C, Ruby 和 JavaScript。舉個例子,在 Object-C 中,我們可以很輕易的動態(tài)去獲取一個對象的任意屬性和方法 - 甚至可以在運行時交換他們的實現(xiàn)。

雖然缺乏動態(tài)性正是 Swift 如此強大的一個重要原因 - 它幫助我們編寫更加可以預測的代碼以及更大的保證了代碼編寫的準確性�, 但是有的時候,能夠編寫具有動態(tài)特性的代碼是非常有用的。

值得慶幸的是,Swift 不斷獲取越來越多的更具動態(tài)性的功能,同時還一直把它的關注點放在代碼的類型安全上。其中的一個特性就是 KeyPath。這周,就讓我們來看看 KeyPath 是如何在 Swift 中工作的,并且有哪些非常酷非常有用的事情可以讓我們去做。

基礎

key paths 基本上讓我們將任何實例屬性引用為單獨的值。因此,它們可以通過表達式傳遞,并使一段代碼能夠獲取或設置一個屬性而無需實際了解該屬性。

Key paths 有三種主要變種:

  • KeyPath:提供對屬性的只讀訪問權限。
  • WritableKeyPath: 提供對具有值語義的可變屬性的讀寫訪問權限(因此所討論的實例也需要是可變的,以便允許的寫入)。
  • ReferenceWritableKeyPath: 只能與引用類型(例如類的實例)一起使用,并為任何可變屬性提供讀寫訪問權限。

還有一些額外的 key paths 類型,即可以減少內部代碼復制并幫助類型擦除,但我們將專注于本文中的主要類型。

讓我們深入查看如何使用 key paths,是什么讓他們有趣和潛在的強大。

功能表達

假設我們正在構建一個應用程序,讓用戶讀取來自 Web 的文章,并且我們有一個用來代表一個這樣的文章的 Article 模型,看起來像這樣:

  1. struct Article { 
  2.     let id: UUID 
  3.     let source: URL 
  4.     let title: String 
  5.     let body: String 

每當我們使用這些模型的數(shù)組時,希望從每個型號中提取一個數(shù)據來形成一個新數(shù)組 —— 例如在以下兩個示例中,我們正在收集所有 ID 和所有文章的來源:

  1. let articleIDs = articles.map { $0.id } 
  2. let articleSources = articles.map { $0.source } 

雖然上面完全有效,因為我們僅僅對從每個實例提取單個值有興趣,但我們真的不需要閉包的全部能力,因此使用 key paths 可能非常適合。

我們將首先擴展 Sequence 來添加 map 的重載,該 map 采用 key paths 而不是閉包。由于我們只對此用例的只讀屬性訪問感興趣,因此我們將使用標準的 KeyPath,并且實際執(zhí)行數(shù)據提取,我們將使用與給定鍵路徑的子項作為參數(shù)使用,如下所示:

  1. extension Sequence { 
  2.     func map<T>(_ keyPath: KeyPath<Element, T>) -> [T] { 
  3.         return map { $0[keyPath: keyPath] } 
  4.     } 
  • 注意:如果您使用的 Swift 5.2 或更高版本,則不再需要上述擴展,因為現(xiàn)在可以將 key paths 自動轉換為函數(shù)。

通過以上擴展,我們現(xiàn)在能夠使用一個非常好的和簡單的語法來從任何序列中的每個元素中提取單個值,使得可以從之前轉換我們的示例:

  1. let articleIDs = articles.map(\.id) 
  2. let articleSources = articles.map(\.source) 

這是非常酷的,但是,當 key paths 真正開始發(fā)光時,它們用于形成稍微復雜的表達式,例如在排序一系列值時。

標準庫能夠自動對包含 Sortable 元素的任何序列進行排序,但對于所有其他類型,我們必須提供自己的排序閉包。但是,使用 key paths,我們可以通過基于 Comparable 的 key patsh 輕松添加用于對任何序列進行排序的支持。就像之前一樣,我們將在序列 Sequence 協(xié)議中添加一個擴展,將給定 key paths 轉換為排序表達式閉包:

  1. extension Sequence { 
  2.     func sorted<T: Comparable>(by keyPath: KeyPath<Element, T>) -> [Element] { 
  3.         return sorted { a, b in 
  4.             return a[keyPath: keyPath] < b[keyPath: keyPath] 
  5.         } 
  6.     } 

使用上面的擴展,我們現(xiàn)在能夠快速且輕松地對任何序列進行排序,只需給出我們想要排序的 key paths。如果我們正在構建任何形式的可排序列表的應用程序 —— 例如包含播放列表的音樂應用程序 —— 這非常方便,因為我們現(xiàn)在自由地對我們的列表進行排序,甚至是嵌套的):

  1. playlist.songs.sorted(by: \.name
  2. playlist.songs.sorted(by: \.dateAdded) 
  3. playlist.songs.sorted(by: \.ratings.worldWide) 

這樣做的似乎只是簡單地添加了一個語法糖,但可以制作一些更復雜的代碼處理的序列同時更容易閱讀,并且還可以幫助減少代碼復制,因為我們現(xiàn)在能夠為任何屬性重用相同的排序代碼。

不需要實例

雖然適量的語法糖很好,但是關鍵路徑的真正的威力來自于,它可以讓我們引用屬性而不必與任意的實例相關聯(lián)。延續(xù)使用之前的音樂主題,假設我們正在開發(fā)一個展示歌曲列表的 App - 并且在 UI 中為這個列表配置 UITableViewCell,我們使用如下的配置類型:

  1. struct SongCellConfigurator { 
  2.     func configure(_ cell: UITableViewCell, for song: Song) { 
  3.         cell.textLabel?.text = song.name 
  4.         cell.detailTextLabel?.text = song.artistName 
  5.         cell.imageView?.image = song.albumArtwork 
  6.     } 

再次聲明,上面的代碼沒有一點問題,但是我們期望以這樣的方式渲染其他的模型的概率非常的高(非常多的 tableView 的 cells 嘗試著去渲染標題,副標題以及圖片而不用去管他們代表的是什么模型)- 因此讓我們看看,我們能否用關鍵路徑的威力去創(chuàng)建一個共享的配置實現(xiàn),讓他可以被任意的模型使用。

讓我們創(chuàng)建一個名叫 CellConfigurator 的泛型,然后因為我們想要用不同的模型去渲染不同的數(shù)據,所以我們將會給它提供一組基于關鍵路徑的屬性 - 我們先渲染其中的一個數(shù)據:

  1. struct CellConfigurator<Model> { 
  2.     let titleKeyPath: KeyPath<Model, String> 
  3.     let subtitleKeyPath: KeyPath<Model, String> 
  4.     let imageKeyPath: KeyPath<Model, UIImage?> 
  5.  
  6.     func configure(_ cell: UITableViewCell, for model: Model) { 
  7.         cell.textLabel?.text = model[keyPath: titleKeyPath] 
  8.         cell.detailTextLabel?.text = model[keyPath: subtitleKeyPath] 
  9.         cell.imageView?.image = model[keyPath: imageKeyPath] 
  10.     } 

上面的實現(xiàn)優(yōu)雅的地方在于,我們現(xiàn)在可以為每個模型定制我們的 CellConfigurator,使用相同的輕量的關鍵路徑語法,如下所示:

  1. let songCellConfigurator = CellConfigurator<Song>( 
  2.     titleKeyPath: \.name
  3.     subtitleKeyPath: \.artistName, 
  4.     imageKeyPath: \.albumArtwork 
  5.  
  6. let playlistCellConfigurator = CellConfigurator<Playlist>( 
  7.     titleKeyPath: \.title, 
  8.     subtitleKeyPath: \.authorName, 
  9.     imageKeyPath: \.artwork 

就像標準庫中的 map 和 sorted 等函數(shù)的操作一樣,我們曾經可能會使用閉包去實現(xiàn) CellConfigurator。然而,通過關鍵路徑,我們能夠使用一個非常好的語法去實現(xiàn)它 - 并且我們也不需要任何的訂制化的操作去不得不通過模型實例去處理 - 使它們變得更加的簡單,更加的具有說服力。

轉化為函數(shù)

目前為止,我們僅僅使用關鍵路徑來讀取值 - 現(xiàn)在讓我們看看我們如何使用它們來動態(tài)的寫值。在很多不同的代碼中,我們常常可以見到一些像下面的代碼一樣的列子 - 我們通過這段代碼來加載一系列的事項,然后在 ListViewController 中去渲染它們,然后當加載操作完成后,我們會簡單的將加載的事項賦值給視圖控制器中的屬性。

  1. class ListViewController { 
  2.     private var items = [Item]() { didSet { render() } } 
  3.  
  4.     func loadItems() { 
  5.         loader.load { [weak self] items in 
  6.             self?.items = items 
  7.         } 
  8.     } 

讓我們看看,通過關鍵路徑賦值能否讓上面的語法簡單一點,并且能夠移除我們經常使用的 weak self 的語法(如果我們忘記對 self 的引用前加上 weak 關鍵字的話,那么就會產生循環(huán)引用)。

既然所有上面我們做的事情都是獲取傳遞給我們閉包的值,并將它賦值給視圖控制器中的屬性 - 那么如果我們真的能夠將屬性的 setter 作為函數(shù)傳遞,會不會很酷呢?這樣我們就可以直接將函數(shù)作為完成閉包傳遞給我們的加載方法,然后所有的事情都會正常執(zhí)行。

為了實現(xiàn)這一目標,首先我們先定義一個函數(shù),讓任意的可寫的轉化為一個閉包,然后為關鍵路徑設置屬性值。為此,我們將會使用 ReferenceWritableKeyPath 類型,因為我們只想把它限制為引用類型(否則的話,我們只會改變本地屬性的值)。給定一個對象,以及給這個對象設置關鍵路徑,我們將會自動將捕獲的對象作為弱引用類型,一旦我們的函數(shù)被調用,我們就會給匹配關鍵路徑的屬性賦值。就像這樣:

  1. func setter<Object: AnyObject, Value>( 
  2.     for object: Object, 
  3.     keyPath: ReferenceWritableKeyPath<Object, Value> 
  4. ) -> (Value) -> Void { 
  5.     return { [weak object] value in 
  6.         object?[keyPath: keyPath] = value 
  7.     } 

使用上面的代碼,我們可以簡化之前的代碼,將弱引用的 self 去除,然后用看起來非常簡潔的語法結尾:

  1. class ListViewController { 
  2.     private var items = [Item]() { didSet { render() } } 
  3.  
  4.     func loadItems() { 
  5.         loader.load(then: setter(for: self, keyPath: \.items)) 
  6.     } 

非常酷有沒有!或許它還能變得更加的酷,當上面的代碼跟更加先進的函數(shù)式編程思想結合在一起的時候,如組合函數(shù) - 因此我們現(xiàn)在可以將多個 setter 函數(shù)和其他的函數(shù)鏈接在一起使用。在接下來的文章中,我們將介紹函數(shù)式編程和組合函數(shù)。

總結

首先,看起來如何以及何時去使用 swift 關鍵路徑這樣的功能有點困難,并且很容易將它們看做是簡單的語法糖。能夠使用更加動態(tài)的方法去引用屬性是一件非常強大的事情,即使閉包通常可以做很多類似的事情,但是輕量的語法以及關鍵路徑的聲明,都使他們能夠成為處理非常多種類的數(shù)據的好的匹配。

 

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

2022-05-11 09:01:54

Swift類型系統(tǒng)幻象類型

2022-07-04 08:54:39

Swift處理器項目

2022-06-13 09:02:06

Swift類型占位符

2022-05-25 09:15:01

Swift 5.6占位符

2021-07-15 16:41:21

Swift查詢函數(shù)

2021-11-17 08:11:35

MySQL

2021-08-31 07:54:24

SQLDblink查詢

2024-04-26 00:00:00

Rust檢查器代碼

2023-11-09 11:56:28

MySQL死鎖

2023-12-18 07:32:08

ChatGPTLLMCoT

2021-03-08 00:11:02

Spring注解開發(fā)

2023-07-28 09:54:14

SQL數(shù)據Excel

2022-08-03 08:11:58

數(shù)據測試同類型

2021-10-30 19:56:10

Flutter按鈕 Buttons

2024-04-15 00:00:00

RabbitMQ死信隊列消息

2021-08-16 08:12:04

SQLMerge用法

2021-09-03 06:46:34

SQL分組集功能

2023-08-29 09:46:12

SQLCTE遞歸

2021-08-16 06:56:21

Slice數(shù)組類型內存

2021-12-11 19:00:54

Java中斷機制
點贊
收藏

51CTO技術棧公眾號

国产精品黄视频| 亚洲视频电影| 欧洲性视频在线播放| 久久亚洲免费视频| 91精品国产99久久久久久红楼| 99久久亚洲国产日韩美女| 色综合中文字幕国产| 国产二级片在线观看| 亚洲综合丁香| 国产精品一区av| 精品91福利视频| 欧美丰满高潮xxxx喷水动漫| 69国产精品视频| 国产精品影视在线观看| 精品乱码一区| 第一sis亚洲原创| 欧美日韩成人在线观看| 美女av在线免费看| 欧美日韩成人综合| 3dmax动漫人物在线看| 波多野结衣在线aⅴ中文字幕不卡 波多野结衣在线一区 | 男女18免费网站视频| 国产高清亚洲一区| 久久久久久久久久久一区| 国产精品一区高清| 欧美激情亚洲综合一区| 末成年女av片一区二区下载| 欧美日韩日本视频| 欧美孕妇孕交| 一区二区欧美国产| 天天爽夜夜爽一区二区三区| 91在线视频观看| 8x8x华人在线| 久久国产精品99久久人人澡| 欧美一区二区三区精美影视| 欧美日韩日本国产亚洲在线| 国产一区二区丝袜| 精品国产一区二区三区久久久蜜臀 | 亚洲在线久久| 欧美中文字幕视频在线观看| 国模大尺度视频一区二区| 精品呦交小u女在线| 福利在线导航136| 日韩精品一区二区三区swag| 99福利在线| 亚洲爱爱爱爱爱| 日韩专区av| 亚洲精品美女网站| 欧美电影免费观看网站| 亚洲午夜未满十八勿入免费观看全集| 免费观看亚洲| 久久久国产一区二区| 午夜日韩影院| 欧美一区二粉嫩精品国产一线天| 女同一区二区三区| 国产欧美日韩综合精品| 国产精品久久久久久久| 91精品国产综合久久香蕉| 先锋资源久久| 国产精品嫩草在线观看| 久久久蜜桃一区二区人| 国产欧美自拍视频| 99久久免费国产| jizzzz日本| 五月天网站亚洲| 国产高清免费av在线| 欧美一区二区不卡视频| 欧美亚洲韩国| 91精品国产精品| 欧美在线观看天堂一区二区三区| 久久免费视频1| 成人丝袜视频网| 麻豆免费网站| 91精品国产乱| 欧美色网在线| 久久久久中文字幕| 亚洲色图二区| 久久久一二三四| 亚洲色图视频网| 日本成人网址| 中文字幕亚洲天堂| 日韩精品水蜜桃| 一区二区不卡在线| 中文字幕一区免费在线观看| 免费黄色在线视频网站| 亚洲免费av网址| 台湾色综合娱乐中文网| 国产一区免费视频| 久久久久久久久久久久久夜| 亚洲欧洲成人| www.欧美日本韩国| 欧洲一区二区三区免费视频| 深夜av在线| 日本国产欧美一区二区三区| 午夜性色一区二区三区免费视频| 国产午夜精品视频一区二区三区| 亚洲精品视频在线| 18免费在线视频| 欧美理论电影在线播放| 亚洲日本视频| 无码人妻丰满熟妇区毛片| 欧美性xxxxxxxx| 2020最新国产精品| 视频在线一区二区三区| 亚洲美女区一区| 国模套图日韩精品一区二区| 成人欧美在线视频| 不卡区在线中文字幕| 国产精品视频二区三区| 欧美xxxx14xxxxx性爽| 中文精品在线| 黄色漫画在线免费观看| 日韩精品黄色网| 国产精品成人一区二区网站软件| 国产精品videossex国产高清 | 18欧美乱大交hd1984| 久久99亚洲网美利坚合众国| 日韩av三级在线观看| 极品少妇一区二区| 亚洲1024| 亚洲**2019国产| 国产盗摄女厕一区二区三区| 国产三级电影在线观看| 91高清免费在线观看| 成人av片在线观看| 国产亚av手机在线观看| 亚洲淫片在线视频| 最新久久zyz资源站| 亚洲无玛一区| 欧美午夜不卡视频| 日韩av大片| 黄色av免费在线播放| 亚洲区一区二区| 亚洲国产影院| 在线观看的av网站| 69视频在线播放| 国产片一区二区| av在线一区不卡| 日本成人性视频| 日韩欧美高清dvd碟片| jizzzz日本| 欧美成人精品一区二区男人小说| 精品久久久国产| sm在线播放| 国产乱码精品一区二区三区卡 | 亚洲看片免费| 两个人hd高清在线观看| 国产suv精品一区二区| 亚洲一区二区三区四区的| 亚洲激情黄色| 亚洲一区二区三区在线免费| 青青草视频在线观看| 最近中文字幕2019第二页视频| 日本三级视频在线播放| 国产乱码在线| 51av在线| 色综合一本到久久亚洲91| 黄色一级片视频| 宅男午夜电影| 国产精品视频分类| 黄色片在线免费观看| 色欲av无码一区二区人妻| 精品在线视频一区二区| 五十路熟女丰满大屁股| 亚洲国产福利| 国产一区二区三区四区五区传媒| 亚洲欧美日韩国产| 亚洲一区在线观看免费 | 国产精品都在这里| 正在播放精油久久| www.xxx麻豆| www.浪潮av.com| 人成福利视频在线观看| 日韩免费电影一区二区| 欧美一区二区三区在线免费观看| 欧美一区二区三区四区五区六区| 女同性恋一区二区| 360天大佬第二季在线观看| 成人综合网站| 日本特黄久久久高潮| 欧洲亚洲精品视频| 奇米四色中文综合久久| 成人黄在线观看| 国产精品精品久久久久久| 日韩欧美在线观看强乱免费| 国产中文字幕在线| 巨胸喷奶水www久久久免费动漫| 亚洲狼人精品一区二区三区| 国产日韩欧美精品一区| 中文字幕av一区二区三区谷原希美| 97在线视频免费| 国产精品一区二区免费在线观看| 欧美精品自拍视频| 在线观看免费网站| 一区二区在线视频观看| 国产在线观看一区二区| 欧美一区二区视频在线观看| 亚洲男子天堂网| 成人免费视频网| chinese少妇国语对白|