Skip to content

Commit 9e25c63

Browse files
committed
修改taskprogress持久化方案,避免使用swiftdata
1 parent 4bc7167 commit 9e25c63

3 files changed

Lines changed: 52 additions & 67 deletions

File tree

README.md

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,9 @@
1111
@main
1212
struct MyApp: App {
1313
init() {
14-
let schema = Schema([
15-
TaskProgress.self, // ⭐ 加入 TaskKit 的 entity
16-
])
17-
do {
18-
modelContainer = try ModelContainer(for: schema)
19-
modelContainer.mainContext.autosaveEnabled = false
20-
} catch {
21-
fatalError("初始化ModelContainer失败。\(URL.applicationSupportDirectory.path(percentEncoded: false))")
22-
}
14+
//原有代码
15+
。。。
16+
//初始化 TaskKit
2317
initTaskKit()
2418
}
2519

@@ -31,9 +25,7 @@ struct MyApp: App {
3125
}
3226

3327
func initTaskKit() {
34-
//初始化 package 的持久化数据库
35-
TaskStore.shared.setup(container: modelContainer)
36-
//初始化 app 有多少 checkpoint
28+
//初始化 app 有多少 task
3729
TaskKit.configure(
3830
tasks: [
3931
AppTask(
@@ -80,6 +72,7 @@ func initTaskKit() {
8072
),
8173
]
8274
)
75+
//有多少奖励,以及奖励和task对应关系
8376
let appRewards = [
8477
Reward(
8578
id: "r1",
@@ -173,9 +166,8 @@ struct UserLevelView: View {
173166
TaskKit 配置应用的初始化入口
174167
AppTask 定义应用中需要引导用户完成的任务
175168
Reward 定义完成任务后可以获得的奖励
176-
TaskProgress 记录用户完成任务的情况,这个是需要持久化的,需要在外部app的持久化数据库中加入这个entity
177169
RewardStore 封装了奖励的加载和保存
178-
TaskStore 封装了任务的完成、查询、setup等逻辑
170+
TaskStore 封装了任务的完成、查询等逻辑
179171
EventCenter 封装了事件的发送、订阅逻辑,定义了事件的多种类型
180172
RewardEngine 封装了奖励的解锁逻辑,解锁奖励,并通知外部app
181173
TaskEngine 封装了任务的完成逻辑,完成任务后更新TaskProgress,并计算是否解锁奖励

Sources/TaskKit/Models/TaskProgress.swift

Lines changed: 0 additions & 22 deletions
This file was deleted.

Sources/TaskKit/Persistence/TaskStore.swift

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,47 +9,62 @@ import Foundation
99

1010
@MainActor
1111
public final class TaskStore {
12+
1213
public static let shared = TaskStore()
14+
private init() { load() }
1315

14-
public var container: ModelContainer!
15-
public var context: ModelContext {
16-
container.mainContext
17-
}
16+
private let key = "task_progress_store"
1817

19-
private init() {}
18+
// taskId -> completedAt
19+
private var completed: [String: Date] = [:]
2020

21-
// 初始化 SwiftData 容器
22-
// 外部注入 SwiftData 的 ModelContainer
23-
public func setup(container: ModelContainer) {
24-
self.container = container
25-
}
21+
// MARK: - Public API
2622

27-
// 查询某个 task 用户完成了吗
2823
public func isDone(_ id: String) -> Bool {
29-
let descriptor = FetchDescriptor<TaskProgress>(predicate: #Predicate { $0.taskId == id })
30-
let result = try? context.fetch(descriptor)
31-
return result?.first?.isDone ?? false
24+
completed[id] != nil
25+
}
26+
27+
public func completedAt(_ id: String) -> Date? {
28+
completed[id]
3229
}
3330

34-
// 修改某个 task 用户已经完成
3531
public func markDone(_ id: String) {
36-
// 先查询是否存在,存在就更新,不存在就插入
37-
38-
let descriptor = FetchDescriptor<TaskProgress>(predicate: #Predicate { $0.taskId == id })
39-
if let result = try? context.fetch(descriptor), let progress = result.first {
40-
progress.isDone = true
41-
progress.completedAt = Date()
42-
} else {
43-
// 不存在就插入
44-
print("不存在,插入")
45-
context.insert(TaskProgress(taskId: id, isDone: true, completedAt: Date()))
46-
}
47-
do {
48-
try context.save()
49-
} catch {
50-
let nsError = error as NSError
51-
fatalError("保存失败:\(nsError), \(nsError.userInfo)")
32+
guard completed[id] == nil else { return }
33+
completed[id] = Date()
34+
save()
35+
}
36+
37+
public func reset(_ id: String) {
38+
if completed.removeValue(forKey: id) != nil {
39+
save()
5240
}
41+
}
5342

43+
public func resetAll() {
44+
completed.removeAll()
45+
save()
5446
}
47+
48+
// MARK: - Persistence
49+
50+
private func save() {
51+
let data = completed.mapValues { $0.timeIntervalSince1970 }
52+
UserDefaults.standard.set(data, forKey: key)
53+
}
54+
55+
private func load() {
56+
guard
57+
let raw = UserDefaults.standard.dictionary(forKey: key) as? [String: TimeInterval]
58+
else { return }
59+
60+
completed = raw.mapValues { Date(timeIntervalSince1970: $0) }
61+
}
62+
63+
// 用于从原来的swfitdata方案迁移过来
64+
public func migrateDone(taskId: String, completedAt: Date) {
65+
guard completed[taskId] == nil else { return }
66+
completed[taskId] = completedAt
67+
save()
68+
}
69+
5570
}

0 commit comments

Comments
 (0)