CoreData是一个强大的框架,用于在Apple的iOS和macOS平台上以对象图形方式管理对象的生命周期和对象图形的持久化。以下是一些个人总结的关键的学习要点,(个人学习笔记,备忘):
CoreData栈的建立与管理:
CoreDataStackManager类是作为单例模式实现的,确保整个应用中有一个统一的数据管理实例。 使用NSPersistentContainer和NSPersistentCloudKitContainer来管理本地和云数据存储。这展示了如何根据用户状态(例如VIP状态)来决定数据存储方式。
//
class CoreDataStackManager {
// 单例模式 - 确保应用中有一个统一的数据管理实例
static let shared = CoreDataStackManager()
// CoreData 的 Persistent 容器,用于本地数据存储
private var persistentContainer: NSPersistentContainer?
CloudKit 的 Persistent 容器,用于云端数据存储
private var cloudKitContainer: NSPersistentCloudKitContainer?
全局变量,用于跟踪迁移重试的次数
var migrationRetryCount = 0
// 私有初始化方法,防止外部实例化
private init() {
initializeContainer()
}
// 初始化容器
private func initializeContainer() {
// 根据用户状态选择合适的容器
if UserStatusManager.shared.isVIP() {
setupCloudKitContainer() // VIP用户使用CloudKit容器
} else {
setupPersistentContainer() // 非VIP用户使用本地Persistent容器
}
}
// 设置 容器
private func setupCloudKitContainer() {
let container = NSPersistentCloudKitContainer(name: "FujiLifeStyle")
//配置容器的各种设置
// 省略具体配置细节代码...
self.cloudKitContainer = container
}
// 设置 Persistent 容器
private func setupPersistentContainer() {
let container = NSPersistentContainer(name: "FujiLifeStyle")
//配置容器的各种设置
// 省略具体配置细节代码...
self.persistentContainer = container
}
// 获取当前使用的容器
public func getContainer() -> NSPersistentContainer? {
return cloudKitContainer ?? persistentContainer
}
// 切换容器
public func switchContainer(toVIP: Bool) {
// 根据新的用户状态初始化对应的容器
if toVIP {
setupCloudKitContainer() // 切换到Cloud容器
} else {
setupPersistentContainer() // 切换到Persistent容器
}
// 这里也可以添加其他逻辑,例如数据迁移等
// 省略数据迁移相关代码...
}
‘’‘
上下文的使用:
NSManagedObjectContext的获取和使用对于在CoreData中进行CRUD(创建、读取、更新、删除)操作至关重要。 performTask方法展示了如何根据执行环境(主线程或后台线程)来使用不同的上下文进行数据操作,确保数据操作的线程安全。
获取 NSManagedObjectContext
public func getContext() -> NSManagedObjectContext? {
return getContainer()?.viewContext
}
数据模型的CRUD操作:
// 增加 - Create
public func createEntity<T: NSManagedObject>(ofType type: T.Type, withData data: [String: Any]) -> T? {
guard let context = getContext(), let entityName = NSStringFromClass(type).components(separatedBy: ".").last else {
return nil
}
if let newObject = NSEntityDescription.insertNewObject(forEntityName: entityName, into: context) as? T {
for (key, value) in data {
newObject.setValue(value, forKey: key)
}
return newObject
}
return nil
}
读取(Read)
// 查询 - Read
public func fetchEntities<T: NSManagedObject>(...) -> [T]? {
// ... 准备请求和执行
do {
let results = try context.fetch(fetchRequest)
return results
} catch {
print("Fetch Error: \(error)")
return nil
}
}
更新(Update)
// 更新 - Update
public func updateEntity(entity: NSManagedObject, withData data: [String: Any]) {
for (key, value) in data {
entity.setValue(value, forKey: key)
}
}
更新操作通过直接修改NSManagedObject
的属性值来进行。此方法接受一个实体和一个键值对字典,然后更新实体的相应属性。
删除(Delete)
// 删除 - Delete
public func deleteEntity(entity: NSManagedObject) {
guard let context = getContext() else {
return
}
context.delete(entity)
}
高级查询和过滤:
在CoreDataStackManager
类中,高级查询和过滤是通过使用复合谓词(NSCompoundPredicate
)实现的。这些高级技术对于构建灵活和高效的数据库查询是至关重要的。同时,正确地保存上下文和维护数据一致性也是非常重要的。
这是我自己使用的谓词查询。
var predicates: [NSPredicate] = []
// 添加基于filmsimulation的谓词
if let filmsimlutation = filmsimlutation, !filmsimlutation.isEmpty {
let simulationPredicate = NSPredicate(format: "filmSimulationID CONTAINS[c] %@", filmsimlutation)
predicates.append(simulationPredicate)
}
// 添加基于tags的谓词
if let tags = tags, !tags.isEmpty {
let tagsPredicate = NSPredicate(format: "tagsSelectAttrid CONTAINS[c] %@", tags)
predicates.append(tagsPredicate)
}
// 将多个谓词组合成一个复合谓词
let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates)
// 使用复合谓词进行查询
// 省略查询相关代码...
}