欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 手游 > 一场陟遐自迩的 SwiftUI + CoreData 性能优化之旅(上)

一场陟遐自迩的 SwiftUI + CoreData 性能优化之旅(上)

2025/5/3 6:42:54 来源:https://blog.csdn.net/mydo/article/details/147060242  浏览:    关键词:一场陟遐自迩的 SwiftUI + CoreData 性能优化之旅(上)

在这里插入图片描述

概述

自从 SwiftUI 诞生那天起,我们秃头码农们就仿佛打开了一个全新的撸码世界,再辅以 CoreData 框架的鼎力相助,打造一款持久存储支持的 App 就像探囊取物般的 Easy。

在这里插入图片描述

话虽如此,不过 CoreData 虽好,稍不留神也可能会让代码执行速度“蜗行牛步”,这该如何解决呢?

在本篇博文中,您将学到如下内容:

  • 概述
  • 1. 当前源代码执行的“小瓶颈”
  • 总结

这是两篇偏向撸码的博文,里面有较多的源代码展示,我们会循序渐进地完成整个优化目标,希望大家能够喜欢。

那还等什么呢?让我们马上开始 CoreData 优化大冒险吧!
Let’s go!!!😉


1. 当前源代码执行的“小瓶颈”

要想小试拳脚,我们必须先有需要优化的代码。下面我就满足大家吧:

struct MonthCountsView: View {@Environment(\.managedObjectContext) var contextlet counter: ProjectCounterlet year: Intlet month: Int@State private var isShowMonthCountsChart = falsevar body: some View {// #1let daysCounts = try! counter.queryDaysCounts(year: year, month: month, context: context)// #2let days = daysCounts.keys.sorted(using: SortDescriptor(\.self, order: .reverse))VStack {Button(isShowMonthCountsChart ? "月计数" : "月计数图表") {withAnimation(.bouncy) {isShowMonthCountsChart.toggle()}}.frame(maxWidth: .infinity, alignment: .leading)if isShowMonthCountsChart {MonthCountsChart(counter: counter, daysCountsDict: daysCounts).frame(minHeight: 200)} else {LazyVGrid(columns: [GridItem](repeating: .init(.adaptive(minimum: 100, maximum: 120), spacing: 8), count: 4)) {ForEach(days, id: \.self) { day inlet dayCounts = daysCounts[day]!let totalCount = dayCounts.totalCountNavigationLink {List {LabeledContent("当日总计数") {Text("\(totalCount)\(counter.unit ?? "")").font(.title2).foregroundStyle(counter.nature.data.color)}Section("单次计数") {if let counts = dayCounts.counts {ForEach(counts, id: \.time) { trace inHStack {Text(Common.timeHHmmFt.string(from: trace.time)).monospacedDigit()Spacer()Text("\(trace.count)\(counter.unit ?? "")").font(.title3).foregroundStyle(counter.nature.data.color)}}}}}.listStyle(.plain).navigationTitle(Common.onlyDateFt.string(from: dayCounts.date))} label: {VStack {HStack {Text("\(Common.tinyDateFt.string(from: dayCounts.date))日").font(.headline).frame(maxWidth: .infinity, alignment: .leading)}.padding(.leading).frame(minHeight: 50)Text("\(totalCount)\(Text("\(counter.unit ?? "")").font(.subheadline))").font(.title).padding(.bottom)}.foregroundStyle(.white).monospacedDigit().background(counter.nature.data.color.gradient.opacity(0.88), in: RoundedRectangle(cornerRadius: 10))}}}}}}
}

上面的代码虽然有点冗长,但本质上却很简单。我们主要做了以下几件事:

  • 使用 isShowMonthCountsChart 状态切换月计数图表和 Grid 显示;
  • 在 #1 代码处,我们调用计数器的 queryDaysCounts 方法,来获取指定月的计数记录,返回的结果是一个 [Int: DayCountsData] 字典;
  • 在 #2 代码处,我们将上述字典所有键反向排序并生成所有日的数组,这会将最近的日排在最前面;

为了进一步便于还未秃小码农们的理解,我们下面将缺失的、与计数相关的数据结构一并贴出来:

struct YearCountsData: Identifiable {var id: String {"\(year)"}let year: Intvar totalCount: Int = 0var monthlyAvg: Float = 0.0var monthsCounts: [Int: MonthCountsData]?var monthsCountSortedAry: [MonthCountsData]? {if let data = monthsCounts {let sortedKeys = data.keys.sorted(using: SortDescriptor(\.self, order: .reverse))return sortedKeys.map { data[$0]! }}return nil}}struct MonthCountsData: Identifiable {var id: String {"\(year).\(month)"}let year: Intlet month: Intvar totalCount: Int = 0var daylyAvg: Float = 0.0var daysCounts: [Int: DayCountsData]?var daysCountSortedAry: [DayCountsData]? {if let data = daysCounts {let sortedKeys = data.keys.sorted(using: SortDescriptor(\.self, order: .reverse))return sortedKeys.map { data[$0]! }}return nil}}struct DayCountsData: Identifiable {var id: Date {date}let date: Datevar totalCount: Int = 0var counts: [(time: Date, count: Int)]?}

如您所见,上面 MonthCountsView 视图的问题在于:每次重新渲染(Rendering)它的 body 内容时,我们都会重新计算 daysCounts 字典的内容(而且这是在主线程中完成的),这无疑有些庸人自扰。

那么,我们该如何进一步优化它的执行效率呢?这看似有些一筹莫展。

别急,在下一篇博文中,我们将会一步步“聚沙成塔”,最终完成整个优化目标,期待吧!


想要进一步系统地学习 Swift 开发的小伙伴们,可以来我的《Swift 语言开发精讲》专栏逛一逛哦:

在这里插入图片描述

  • 《Swift 语言开发精讲》

总结

在本篇博文中,我们介绍了 SwiftUI + CoreData 代码在执行时遇到的一个效率瓶颈,并给出了问题相关的详细源代码。

感谢观赏,我们下一篇再见吧!😎

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词