iOS首次启动App时如何仅一次生成CoreData表格初始非空数据
CoreData 仅首次启动填充预置数据实现方案
核心问题原因
把预置数据逻辑写在viewDidLoad里重复生成的本质原因是:viewDidLoad属于页面生命周期方法,每次页面实例化加载时都会触发,和应用启动次数没有绑定关系,必然会出现重复执行的问题。
正确实现逻辑
- 不要将预置数据生成逻辑放在任何页面的生命周期方法内,应该把逻辑放在Core Data栈初始化完成、UI加载前的节点执行
- 用
UserDefaults存储独立的标记位判断是否已经完成过初始数据导入,不要通过查询CoreData表是否为空来判断,避免用户手动清空所有数据后被强制重新插入默认数据 - 标记位必须在预置数据成功写入CoreData并保存完成后再更新,防止写入失败后下次启动无法重试补数据
推荐放置位置
如果你使用NSPersistentContainer搭建CoreData栈,直接把导入逻辑放在loadPersistentStores的完成回调中即可,这个节点CoreData的上下文已经完全可用,且还没到页面渲染阶段,不会出现空表格闪一下再出现数据的问题。
如果是手动搭建CoreData栈,就在持久化存储加载完成、托管对象上下文初始化成功后,把逻辑放在AppDelegate的application(_:didFinishLaunchingWithOptions:)方法中执行。
代码示例
// 预置数据导入标记的key private let hasFinishedPreloadDataKey = "hasFinishedPreloadDataKey" // NSPersistentContainer 加载存储的回调内实现逻辑 persistentContainer.loadPersistentStores { storeDescription, loadError in guard loadError == nil else { // 自行处理存储加载异常 return } let viewContext = persistentContainer.viewContext // 已经导入过预置数据就直接返回 guard !UserDefaults.standard.bool(forKey: hasFinishedPreloadDataKey) else { return } // 在此处编写你的预置数据生成、插入逻辑 // 示例:插入两条默认列表项 let defaultItem1 = ListItem(context: viewContext) defaultItem1.title = "默认待办1" defaultItem1.createTime = Date() let defaultItem2 = ListItem(context: viewContext) defaultItem2.title = "默认待办2" defaultItem2.createTime = Date() // 保存数据,成功后再打标记 do { try viewContext.save() UserDefaults.standard.set(true, forKey: hasFinishedPreloadDataKey) } catch { print("初始预置数据保存失败: \(error.localizedDescription)") } }
DiffableDataSource 适配注意事项
- 因为预置数据导入在UI加载前就已经完成,页面走到
viewDidLoad生命周期时,通过NSFetchedResultsController或者Core Data查询接口已经能拿到完整的预置数据,直接构建snapshot应用到DiffableDataSource即可,不会出现空表问题 - 不要在DiffableDataSource的snapshot应用回调中插入任何数据写入逻辑,避免数据驱动更新时触发重复写入
注意:如果你的应用需要支持版本迭代新增预置数据,可以把标记位从布尔值改成当前应用版本号,每次启动判断本地存储的版本号低于当前应用版本时,执行对应版本的新增预置数据导入,再更新存储的版本号即可。
内容的提问来源于stack exchange,提问作者Nuri
相关产品推荐
相关产品推荐

