做一网站要学些什么软件,郑州网页开发的公司,设计网站怎么收费,网站建设作业指导书概览
小伙伴们可能不知道#xff1a;在 Swift 语言中隐藏着大量看似“其貌不扬”实则却让秃头码农们“高世骇俗”#xff0c;堪称卧虎藏龙的各种秘技。 其中#xff0c;有一枚“不起眼”的小家伙称之为键路径#xff08;Key Paths#xff09;。如若将其善加利用#xff…
概览
小伙伴们可能不知道在 Swift 语言中隐藏着大量看似“其貌不扬”实则却让秃头码农们“高世骇俗”堪称卧虎藏龙的各种秘技。 其中有一枚“不起眼”的小家伙称之为键路径Key Paths。如若将其善加利用必将在实际撸码中大放异彩如虎添翼 在本篇博文中您将学到如下内容 概览1. 一窥门径键路径Key Paths初步2. 功能快速简化之妙用3. 将键路径当做方法传递总结 本篇和下一篇皆为看似“平淡无奇”的键路径“凤凰涅槃”、逆袭重生的“励志”博文到底如何且看分解
闲言少叙Let’s change our destiny against the heavens 1. 一窥门径键路径Key Paths初步
我们知道 Swift 语言最初的设计重点是编译时安全和静态类型。因此它势必会缺乏那些更加关注运行时语言如 Objective-C、Ruby 和 JavaScript中常见的那种动态特性。例如在 Objective-C 中我们可以在运行时动态访问对象中的任何属性和方法甚至交换、修改其相关的实现。 想要了解更多 Swift 动态机制内容的小伙伴们请移步如下链接观赏精彩的内容
『番外篇二』Swift “黑魔法”之动态获取类实例隐藏属性的值SwiftUI 利用 Swizz 黑魔法为系统创建的默认对象插入新协议方法(五)SwiftUI 利用 Swizz 黑魔法为系统创建的默认对象插入新协议方法(六)SwiftUI 如何在运行时从底层动态获取任何 NSObject 对象实例『番外篇五』SwiftUI 进阶之如何动态获取任意视图的 tag 和 id 值 虽然这种缺乏动态性的特点可能恰恰是 Swift 如此强大的主要缘由因为它可以帮助我们编写可预测性更强的逻辑并且有更大的概率撸出“正确”的代码。
不过有时能够以更动态的方式处理我们的实现夙愿也会非常有用。
谢天谢地进化中的 Swift 语言不断汲取着越来越多本质上更动态的功能同时也仍然专注于类型的安全性这其中一个不可或缺的特性便是键路径Key Paths。 在 Swift 中广义的键路径是指一种动态访问和修改对象属性的机制而狭义的键路径则用来表示特定根类型上特定属性值的类型。 一般来说存在三种键路径
KeyPath: 最常见的形式用来提供到某一类型特定属性的只读路径WritableKeyPath: 用值语义value semantics提供到某一类型特定属性的读写路径因而该类型的实例也必须是可写的ReferenceWritableKeyPath: 和 WritableKeyPath 类似不过只能用在引用类型上比如类 除了上面最常见的三种键路径类型以外还有其它一些键路径。它们主要被用于减少内部代码重复或帮助类型抹除Type erase等情况限于篇幅就不在本文中介绍了
如果想要进一步了解这些额外键路径类型请小伙伴们移步如下链接观赏进一步的内容
Key-Path ExpressionsKeyPath Documentation 在初步了解键路径的基本概念之后下面就让我们深入探寻一番如何使用关键路径以及它们因何而有趣、又因何而强大吧。
2. 功能快速简化之妙用
假设我们正在构建一款应用程序它允许用户阅读来自网页的内容。我们设计了一个 Article 模型用来表示 Web 页面中对应的文章如下所示
struct Article {let id: UUIDlet source: URLlet title: Stringlet body: String
}在大多数情况下每当我们使用这样的模型数组时通常希望从数组每个元素中提取一块数据以形成新的数组 —— 例如在下面两个示例中我们从一组文章Article中收集了所有的 id 和 source
let articleIDs articles.map { $0.id }
let articleSources articles.map { $0.source }虽然上面的代码并没有什么错不过由于我们的愿望只是单纯地从数组元素的单个属性中提取值所以使用闭包看似有些大材小用了。
在这里换为键路径会更加恰如其分。
extension Sequence {func mapT(_ keyPath: KeyPathElement, T) - [T] {return map { $0[keyPath: keyPath] }}
}如上代码所示我们为序列Sequence增加了一个协议扩展方法 map该方法的参数为序列元素任意属性的键路径。我们在 map 方法的实现中巧妙利用 Swift 下标 subscript语法糖“有胆有识”的访问了序列元素属性的值。
这样一来我们即可以用非常 Nice 的语法来提取序列元素任意属性的内容啦所以之前的代码可以重构为如下形式了
let articleIDs articles.map(\.id)
let articleSources articles.map(\.source)虽然这让秃头码农们觉得很酷不过键路径真正熠熠生辉的地方是当它们用于构建更复杂表达式的时候比如在对数组排序时。
众所周知Swift 标准库能够自动对包含 Sortable 元素的任何序列进行排序但对于所有其它类型我们必须提供自己的排序闭包。然而使用键路径我们也可以轻而易举地添加对基于可比较键路径序列元素进行排序的支持。
与之前类似我们将在 Sequence 协议上添加一个扩展方法它的作用是将给定的键路径转换为排序表达式闭包
extension Sequence {func sortedT: Comparable(by keyPath: KeyPathElement, T) - [Element] {return sorted { a, b inreturn a[keyPath: keyPath] b[keyPath: keyPath]}}
}有了上面的“铺垫”我们现在只需给出想要排序的键路径即可优哉游哉地对任何类型元素的序列进行排序啦。
假若我们正在构建的 App 需要处理任何形式的可排序列表例如包含播放列表的音乐应用程序 —— 这将非常方便因为我们现在可以根据任何可比较属性甚至嵌套属性对列表进行排序了
playlist.songs.sorted(by: \.name)
playlist.songs.sorted(by: \.dateAdded)
playlist.songs.sorted(by: \.ratings.worldWide)上面代码看起来就像在优雅地添加“甜美的”语法糖这既可以使处理序列复杂的代码更容易阅读也可以帮助减少代码重复DRY因为小伙伴们现在可以“为所欲为”的向任何属性重用相同的排序逻辑啦很棒哦
3. 将键路径当做方法传递
一个好消息是从 Swift 5.2 开始上面 Sequence 扩展中的 map 方法已不再需要因为键路径如今可以自动地转换为方法啦converted into functions
这可能只是 Swift 语言进化中的一小步但却是键路径“功成名就”的一大步因为它会使序列上功能闭包的调用看起来更加“青出于蓝” —— 因为我们现在可以直接传递该属性的键路径了
struct Movie {var name: Stringvar isFavorite: Bool...
}let movies: [Movie] loadMovies()// 等价于 movies.map { $0.name }
let movieNames movies.map(\.name)// 等价于 movies.filter { $0.isFavorite }
let favoriteMovies movies.filter(\.isFavorite)总结
在本篇博文中我们先是介绍了 Swift 语言中“简约却不简单”的键路径Key Paths机制接着讨论了将它用来简化逻辑以及当成方法functions传递的美妙瞬间。
我们将在下一篇博文中继续介绍如何用键路径超越对象实例特例化specialize数据模型以及用可写键路径彻底摆脱“引用循环”让简化代码“一蹴而就”。
感谢观赏下一篇再会喽