Core Data is a Data persistence framework introduced in iOS3.0. The biggest advantage over SQLite is that it supports object storage. Apple’s official documentation says it simplifies database operations. Using Core Data does reduce the number of SQL statements in your code significantly.

However, the solution of choice for persistence is still mostly FMDB. The biggest reason, I suspect, may be performance.

What is Core Data

Core Data is a model layer technology that helps developers create model layers that represent application state. It is also a persistence technique that persists the state of model objects to disk. It is a completely uI-level independent framework, designed as a model-level framework.

Core Data is not an O/RM, but it can do more than AN O/RM. It is also not an SQL wrapper. It uses SQL by default, but it is a higher level abstraction.

The stack

Core Data has quite a few components available. When all the components are bundled together, we call it the Core Data stack, and the stack has two main parts.

One section is about object graph management, which is exactly what you need to be good at and know how to use it. The other part is about persistence, for example, saving the state of your model object and then restoring the state of your model object.

The stack structure is as follows

NSPersistentStoreCoordinator is located in a local store file with the cache (NSManagedObjectContext) between a persistence layer, it is real operating local file database.

Ns-managedobjectcontext is a context for managed data. It is actually a caching layer for all database operations. All operations are cached first to avoid a lot of disk I/O. Can submit database operations to the persistence layer (NSPersistentStoreCoordinator), by the persistence layer one-time write to the database file.

Ns-managed Object is a managed data record that corresponds to a table in the database.

Additionally, Core Data can attach multiple stores to the same persistent storage coordinator, and there are many storage types to choose from in addition to the SQL format. The most common scheme is as follows

The actual use

Here are the elements of an Event table defined by the author

Defining the data model

class MXWEventModel: NSObject {
    var id: Int64
    var time: Date
    var title: String
    var detail: String
    var addr: String
    
    init(id: Int64, title: String, detail: String, addr: String, time: Date){}
}
Copy the code

The new data

let context = persistentContainer.viewContext

public func add(model: AnyObject) {
	let eventModel: MXWEventModel = model as! MXWEventModel
	let entity = NSEntityDescription.entity(forEntityName: @"MXWEvent".in: context!)
	let obj = NSManagedObject(entity: entity! , insertInto: context) obj.setValue(eventModel.id, forKey:"id")
	obj.setValue(eventModel.title, forKey: "title")
	obj.setValue(eventModel.detail, forKey: "detail")
	obj.setValue(eventModel.time, forKey: "time")
	obj.setValue(eventModel.addr, forKey: "addr")
	do {
		trycontext? .save() }catch {
		print(error)
	}
}
Copy the code

Delete the data

public func delete(id: Int64) {
	let request = NSFetchRequest<NSFetchRequestResult>(entityName: @"MXWEvent")
	request.predicate = NSPredicate(format: "id==\(id)")
	let deleteRequest = NSBatchDeleteRequest(fetchRequest: request)
	do {
		trycontext? .execute(deleteRequest) }catch {
		print(error)
	}
}
Copy the code

Modify the data

public func update(id: Int64, model: AnyObject) {
	let eventModel: MXWEventModel = model as! MXWEventModel
	let request = NSFetchRequest<NSFetchRequestResult>(entityName: @"MXWEvent")
	request.predicate = NSPredicate(format: "id==\(id)")
	do {
		let eventObj = trycontext? .fetch(request)letupdateObj = eventObj? .firstas! NSManagedObject
		updateObj.setValue(eventModel.title, forKey: "title")
		updateObj.setValue(eventModel.detail, forKey: "detail")
		updateObj.setValue(eventModel.time, forKey: "time")
		updateObj.setValue(eventModel.addr, forKey: "addr")
		do {
			trycontext? .save() }catch {
			print(error)
		}
	} catch {
		print(error)
	}
}
Copy the code

To find the data

public func fetch(id: Int64) -> AnyObject? {
	let request = NSFetchRequest<NSFetchRequestResult>(entityName: @"MXWEvent")
	request.predicate = NSPredicate(format: "id==\(id)")
	do {
		let r = trycontext? .fetch(request)for data in r as! [NSManagedObject] {
			let m = MXWEventModel(id: data.value(forKey: "id") as! Int64, title: data.value(forKey: "title") as! String, detail: data.value(forKey: "detail") as! String, addr: data.value(forKey: "addr") as! String, time: data.value(forKey: "time") as! Date)
			return m
		}
	} catch {
		print(error)
	}
}
Copy the code

Advanced features

Data migration

During functional iterations, it is inevitable that you will encounter.xcDatamodeld files that need to be modified. For example, adding or deleting an entity, adding or deleting attributes of an existing entity, and so on. If the developer does not set the data migration, the original data will be cleared after the update, so the data migration operation needs to be performed.

Core Data allows lightweight Data migration. The system will automatically analyze differences and map Data. This method is only suitable for simple operations such as adding and deleting entities or adding and deleting attributes. There is also a fairly complex custom data migration.

// MARK: - Core Data stack

lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "Demo")
    container.loadPersistentStores(completionHandler: { storeDescription, error in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error).\(error.userInfo)")}/ / set the data migration (shouldMigrateStoreAutomatically defaults to true)
        if let sDescription: NSPersistentStoreDescription = storeDescription as NSPersistentStoreDescription {
            sDescription.shouldMigrateStoreAutomatically = true
            sDescription.shouldInferMappingModelAutomatically = false}})return container
}()
Copy the code

thinking

As for Core Data, Apple officially launched it a long time ago, but developers didn’t like it. The author is also thinking about this problem during this period of learning.

The following are the points of attention encountered in the author’s study:

  1. There are no auto-increment Data types in Core Data. Because Core Data can’t be used with database thinking, it’s easy to explain.
  2. Set the merge context policy to reduce data migration.
  3. It is best to use multi-threading to further improve performance.

Finally, performance comparisons are given at the beginning of the article. However, I don’t think there’s a lot of Data written on the client side, and performance shouldn’t be a reason to reject the Core Data solution, as long as developers are careful with it. On the other hand, Core Data has great support for iCloud, as well as Data migration and backup, which can be easily implemented. In my opinion, we can consider using it to do client-side data persistence.

Reference documentation

Core Data Programming Guide