
Swift数据结构库优化可识别元素集合管理
swift-identified-collections库为Swift开发者提供高性能数据结构,用于管理唯一标识元素集合。它解决了普通数组处理可识别元素的性能和稳定性问题。核心组件IdentifiedArray结合了OrderedDictionary的优势,提供了更易用的API。该库适用于SwiftUI应用和Composable Architecture框架开发,提高了代码效率和可靠性。
一个用于以人体工程学和高性能方式处理可识别元素集合的数据结构库。
在为应用程序的状态建模集合元素时,很容易想到使用标准的Array。然而,随着应用程序变得更加复杂,这种方法可能会在多个方面出现问题,包括意外对错误的元素进行修改,甚至导致崩溃。😬
例如,如果你正在使用SwiftUI构建一个"待办事项"应用程序,你可能会将单个待办事项建模为一个可识别的值类型:
struct Todo: Identifiable { var description = "" let id: UUID var isComplete = false }
然后你会在应用程序的视图模型中将这些待办事项的数组作为已发布的字段持有:
class TodosViewModel: ObservableObject { @Published var todos: [Todo] = [] }
视图可以非常简单地渲染这些待办事项的列表,而且由于它们是可识别的,我们甚至可以省略List的id参数:
struct TodosView: View { @ObservedObject var viewModel: TodosViewModel var body: some View { List(self.viewModel.todos) { todo in ... } } }
如果你的部署目标设置为最新版本的SwiftUI,你可能会尝试将绑定传递给列表,以便每一行都可以对其待办事项进行可变访问。这对于简单的情况来说是可行的,但一旦你引入副作用(如API客户端或分析),或者想要编写单元测试,你就必须将这个逻辑推送到视图模型中。这意味着每一行都必须能够将其操作传回视图模型。
你可以通过在视图模型中引入一些端点来实现这一点,比如当一行的完成状态切换时:
class TodosViewModel: ObservableObject { ... func todoCheckboxToggled(at id: Todo.ID) { guard let index = self.todos.firstIndex(where: { $0.id == id }) else { return } self.todos[index].isComplete.toggle() // TODO: 使用API客户端在后端更新待办事项 } }
这段 代码足够简单,但它可能需要对数组进行完整的遍历才能完成任务。
也许让一行将其索引传回视图模型会更高效,然后它可以通过索引直接修改待办事项。但这会使视图变得更复杂:
List(self.viewModel.todos.enumerated(), id: \.element.id) { index, todo in ... }
这还不算太糟,但目前它甚至无法编译。一个演进提案可能很快会改变这一点,但在此之前,List和ForEach必须传递一个RandomAccessCollection,这可能最简单的方法是构造另一个数组:
List(Array(self.viewModel.todos.enumerated()), id: \.element.id) { index, todo in ... }
这可以编译,但我们刚刚将性能问题转移到了视图中:每次评估这个body时,都有可能分配一个全新的数组。
但即使可以将枚举集合直接传递给这些视图,通过索引来识别可变状态的元素也会引入一些其他问题。
虽然我们确实可以大大简化和提高通过索引下标修改元素的任何视图模型方法的性能:
class TodosViewModel: ObservableObject { ... func todoCheckboxToggled(at index: Int) { self.todos[index].isComplete.toggle() // TODO: 使用API客户端在后端更新待办事项 } }
但是我们添加到这个端点的任何异步工作都必须非常小心,不要在之后使用这个索引。索引不是一个稳定的标识符:待办事项可以随时移动和删除,一个瞬间标识"买生菜"的索引可能下一刻就标识"打电话给妈妈",更糟糕的是,可能是一个完全无效的索引,导致应用程序崩溃!
class TodosViewModel: ObservableObject { ... func todoCheckboxToggled(at index: Int) async { self.todos[index].isComplete.toggle() do { // ❌ 可能会更新错误的待办事项,或导致崩溃! self.todos[index] = try await self.apiClient.updateTodo(self.todos[index]) } catch { // 处理错误 } } }
每当你需要在执行某些异步工作后访问特定的待办事项时,你_必须_遍历数组:
class TodosViewModel: ObservableObject { ... func todoCheckboxToggled(at index: Int) async { self.todos[index].isComplete.toggle() // 1️⃣ 在开始异步工作之前获取待办事项的id引用 let id = self.todos[index].id do { // 2️⃣ 在后端更新待办事项 let updatedTodo = try await self.apiClient.updateTodo(self.todos[index]) // 3️⃣ 在异步工作完成后找到待办事项的更新索引 let updatedIndex = self.todos.firstIndex(where: { $0.id == id })! // 4️⃣ 更新正确的待办事项 self.todos[updatedIndex] = updatedTodo } catch { // 处理错误 } } }
标识集合旨在通过提供以人体工程学和高性能方式处理可识别元素集合的数据结构来解决所有这些问题。
大多数情况下,你可以简单地将Array替换为IdentifiedArray:
import IdentifiedCollections class TodosViewModel: ObservableObject { @Published var todos: IdentifiedArrayOf<Todo> = [] ... }
然后你可以通过基于id的下标直接修改元素,无需遍历,即使在执行异步工作后也是如此:
class TodosViewModel: ObservableObject { ... func todoCheckboxToggled(at id: Todo.ID) async { self.todos[id: id]?.isComplete.toggle() do { // 1️⃣ 在后端更新待办事项并在todos标识数组中修改它。 self.todos[id: id] = try await self.apiClient.updateTodo(self.todos[id: id]!) } catch { // 处理错误 } // 没有步骤 2️⃣ 😆 } }
你还可以简单地将标识数组传递给List和ForEach等视图,而不会出现任何复杂性:
List(self.viewModel.todos) { todo in ... }
标识数组设计用于与SwiftUI应用程序以及使用Composable Architecture编写的应用程序集成。
IdentifiedArray是Apple的Swift Collections中OrderedDictionary类型的轻量级包装器。它具有许多相同的性能特征和设计考虑,但更适合解决在应用程 序状态中保存_可识别_元素集合的问题。
IdentifiedArray不会暴露任何可能导致破坏不变性的OrderedDictionary细节。例如,OrderedDictionary<ID, Identifiable>可以自由地保存其标识符与其键不匹配的值,或多个值可能具有相同的id,而IdentifiedArray不允许这些情况发生。
与OrderedSet不同,IdentifiedArray不要求其Element类型符合Hashable协议,这可能难以或不可能实现,并引入了关于哈希质量等问题。
IdentifiedArray甚至不要求其Element符合Identifiable。就像SwiftUI的List和ForEach视图接受一个id键路径来获取元素的标识符一样,IdentifiedArray可以使用键路径构造:
var numbers = IdentifiedArray(id: \Int.self)
IdentifiedArray设计用于匹配OrderedDictionary的性能特征。它已经使用Swift Collections Benchmark进行了基准测试:

如果你想讨论这个库或有关如何使用它解决特定问题的问题,有几个地方可以与其他Point-Free爱好者讨论:
Identified Collections的最新API文档可在这里获得。
这些概念(以及更多)在Point-Free中得到了深入探讨,这是一个由Brandon Williams和Stephen Celis主持的探索函数式编程和Swift的视频系列。
在Composable Architecture中使用IdentifiedArray的内容在以下Point-Free集中进行了探讨:
所有模块都在MIT许可证下发布。有关详细信息,请参阅LICENSE。


免费创建高清无水印Sora视频
Vora是一个免费创建高清无水印Sora视频的AI工具


最适合小白的AI自动化工作流平台
无需编码,轻松生成可复用、可变现的AI自动化工作流

大模型驱动的Excel数据处理工具
基于大模型交互的表格处理系统,允许用户通过对话方式完成数据整理和可视化分析。系统采用机器学习算法解析用户指令,自动执行排序、公式计算和数据透视等操作,支持多种文件格式导入导出。数据处理响应速度保持在0.8秒以内,支持超过100万行数据的即时分析。


AI辅助编程,代码自动修复
Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。


AI论文写作指导平台
AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。


AI一键生成PPT,就用博思AIPPT!
博思AIPPT,新一代的AI生成PPT平台,支持智能生成PPT、AI美化PPT、文本&链接生成PPT、导入Word/PDF/Markdown文档生成PPT等,内置海量精美PPT模板,涵盖商务、教育、科技等不同风格,同时针对每个页面提供多种版式,一键自适应切换,完美适配各种办公场景。


AI赋能电商视觉革命,一站式智能商拍平台
潮际好麦深耕服装行业,是国内AI试衣效果最好的软件 。使用先进AIGC能力为电商卖家批量提供优质的、低成本的商拍图。合作品牌有Shein、Lazada、安踏、百丽等65个国内外头部品牌,以及国内10万+淘宝、天猫、京东等主流平台的品牌商家,为卖家节省将近85%的出图成本,提升约3倍出图效率,让品牌能够快速上架。


企业专属的AI法律顾问
iTerms是法大大集团旗下法律子品牌,基于最先进的大语言模型(LLM)、专业的法律知识库和强大的智能体架构,帮助企业扫清合规障碍,筑牢风控防线,成为您企业专属的AI法律顾问。


稳定高效的流量提升解决方案,助力品牌曝光
稳定高效的流量提升解决方案,助力品牌曝光


最新版Sora2模型免费使用,一键生成无水印视频
最新版Sora2模型免费使用,一键生成无水印视频
最新AI工具、AI资讯
独家AI资源、AI项目落地

微信扫一扫关注公众号