一款简明现代的用于 iOS 的 Core Data 栈,用 Swift 编写。
CoreDataManager 是一个旨在简化 Core Data 配置和使用的小型 Swift 框架。
它作为一个典型的基于 NSPersistentContainer
的 Core Data 栈来运作,提供对主和后台上下文访问。它还以同步/异步方式提供对 CRUD 操作的所有访问,并处理一些大多数用户都面临的常见线程陷阱。
特点
- 直接访问主和后台 Core Data 上下文
- 易用的 CRUD 方法
- 支持基本多线程
要求
- iOS 13.0+
- Xcode 11.3
安装
CocoaPods
CocoaPods 是 Cocoa 项目的依赖管理器。有关使用和安装说明,请访问他们的网站。要使用 CocoaPods 将 CoreDataManager 集成到 Xcode 项目中,请将其在 Podfile
中指定。
pod 'GECoreDataManager'
设置
在开始使用CoreDataManager之前,您需要设置堆栈。这是通过调用异步的setup
方法来完成的。您必须传递模型名称、堆栈类型和完成块作为参数。完成块将包含一个Result实例作为参数,这样您可以轻松知道是否发生了失败。
您可以通过调用其单例实例来访问CoreDataManager堆栈,然后在其上调用setup
。
import CoreDataManager
// Other imports ...
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let completionBlock = { (result: Result<Void,Error>) in
switch result {
case .success():
print("Core Data setup ended")
case .failure(let error):
print("Core Data setup error: \(error)")
}
}
let stack = CoreDataManager.shared
stack.setup(withModel:"Test", type: .inmemory ,completion: completionBlock )
// ...
}
}
CoreDataManager提供三种不同类型的基本堆栈,基于NSPersistentContainer
类型。这些是:.standard
、.inmemory
和.binary
。您通常会在大多数情况下使用.standard
类型,并在编写单元测试时使用.inmemory
。
基本用法
CoreDataManager提供两种操作方式。第一种是一种传统方法,其中堆栈为您提供访问两个NSManagedObjectContext
实例的方式。一个与主队列相关联,另一个与后台队列相关联。您必须正确使用它们。另一种方式是使用提供的CRUD操作方法。它们与直接使用上下文相比灵活性较低,但简化了操作,并处理了大多数人使用Core Data时面临的典型线程问题。
通过上下文使用
如果您通过直接上下文访问使用CoreDataManager,您有两个属性
- mainContext
- backgroundContext
这些上下文本质上是与其队列相关联的,所以任何使用它们的操作都必须考虑到这一点。
正如其名所示,mainContext
与主队列相关联,必须始终在此队列中使用。通过此上下文检索的对象也将与该队列相关联。如果您尝试从任何其他线程访问其对象,它将崩溃。这是标准的Core Data行为,无法避免。
另一方面,backgroundContext
将允许您从后台队列使用它并访问其对象。与主队列一样,上下文及其对象与后台队列相关联,因此从其他线程访问将导致崩溃。
通过CRUD操作使用
如果您使用CoreDataManager通过CRUD操作,通常会有两种方法:同步和异步。唯一的例外是,由于其自身的性质,没有异步更新。
根据方法,您可能需要提供一个代表您想要执行的操作的块,或者您需要提供一个NSFetchRequest
。您将通过方法返回类型或通过完成块始终收到表示成功或失败的Result
实例。
在示例项目中,您可以找到如何使用这些方法的示例。
CRUD示例
这些示例都从主线程调用。CoreDataManager将在执行方法的异步版本时自动在后台执行操作。如果异步操作有要返回的对象,它们将自动发送到主队列,如果需要,允许直接修改UI。
同步创建
// Creation block, TodoTask is an NSManagedObject subclass
let createBlock = { (context:NSManagedObjectContext) in
let task = TodoTask(context: context)
task.title = "To do task"
task.done = false
}
// stack is already inited...
let result = stack.createObject(using:createBlock)
switch result {
case .success:
print("Created objects successfuly")
case .failure(let error):
print("Error creating: \(error.localizedDescription)")
}
异步创建
// Creation block, TodoTask is an NSManagedObject subclass
let createBlock = { (context:NSManagedObjectContext) in
let task = TodoTask(context: context)
task.title = "To do task"
task.done = false
}
// Completion block, has a Result parameter
let completionBlock = { (result: Result<Void,Error>) in
switch result {
case .success:
print("Created objects successfuly")
case .failure(let error):
print("Error creating: \(error.localizedDescription)")
}
}
// stack is already inited...
stack.createObjectAsync(using:createBlock, completion: completionBlock)
同步获取
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "TodoTask")
// stack is already inited...
let result = stack.fetchObject(using: fetchRequest)
switch result {
case let .success(objects):
let castedObjects = objects.map { (object) -> TodoTask in
return object as! TodoTask
}
print(castedObjects)
case .failure(let error):
print("Error fetching: \(error.localizedDescription)")
}
异步抓取
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "TodoTask")
let completionBlock = { (result : Result<[NSManagedObject],Error>) in
switch result {
case let .success(objects):
let castedObjects = objects.map { (object) -> TodoTask in
return object as! TodoTask
}
print(castedObjects)
case .failure(let error):
print("Error fetching: \(error.localizedDescription)")
}
}
// stack is already inited...
stack.fetchObjectAsync(using: fetchRequest, completion: completionBlock)
同步更新
// TodoTask fetched anywhere...
let task = fetchedTasks.first!
let updateBlock = {
task.done = true // Was false
}
// stack is already inited...
let updateResult = stack.updateObject(using: updateBlock)
switch updateResult {
case .success:
print("Updated objects successfuly")
case .failure(let error):
print("Error updating: \(error.localizedDescription)")
}
同步删除
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "TodoTask")
// stack is already inited...
let result = stackManager.deleteObject(using: fetchRequest)
switch result {
case .success(let deletedCount):
print("Deleted \(deletedCount) 'Todo' tasks")
case .failure(let error):
print("Error updating: \(error.localizedDescription)")
}
异步删除
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "TodoTask")
let completionBlock = { (result : Result<Int,Error>) in
switch result {
case let .success(deletedCount):
print("Deleted \(deletedCount) 'Todo' tasks")
case .failure(let error):
print("Error updating: \(error.localizedDescription)")
}
}
// stack is already inited...
stack.deleteObjectAsync(from: fetchRequest, completion: completionBlock)
示例
下载示例项目,查看如何使用CoreDataManager的CRUD操作。
贡献
如果您想为 CoreDataManager 贡献,请检查 LICENSE
文件以获取更多信息。
元数据
Guillem Espejo – [email protected]
基于MIT许可证发布。有关更多信息,请参阅。