Swift实现CoreData存储数据
之前写过一篇介绍iOS数据存储方法的文章,包含:FMDB,SQLite3 ,Core Data,Plist,偏好设置,归档。
链接:https://www.jianshu.com/p/e88880be794f
本文则是介绍Swift中CoreData的基本使用。
文中示例代码GitHub地址:Demo
![](https://img.haomeiwen.com/i3873004/ad4f079ba055f7db.gif)
目录
一、 图形化创建模型
二、 手动创建模型并实现AppDelegate中的代码
三、 创建并实现CoreDataManager
一、图形化创建模型(这一小节的内容我的另一篇文中也有,如已经熟悉,或想要直接手动创建模型,可以直接看第二小节正式进入Swift)
创建项目的时候,勾选下图中的Use Core Data选项,工程中会自动创建一个数据模型文件。当然,你也可以在开发中自己手动创建。
![](https://img.haomeiwen.com/i3873004/22674d6bf7b0bd04.jpg)
下图就是自动创建出来的文件
![](https://img.haomeiwen.com/i3873004/99d5db789d967547.png)
如果没有勾选,也可以在这里手动创建。
![](https://img.haomeiwen.com/i3873004/251764adcf0b0974.png)
点击Add Entity之后,相当一张数据表。表的名称自己在上方定义,注意首字母要大写。
在界面中还可以为数据实体添加属性和关联属性。
![](https://img.haomeiwen.com/i3873004/c1e7ddcc0bc1119c.png)
Core Data属性支持的数据类型如下
![](https://img.haomeiwen.com/i3873004/79805e0cf409be6d.png)
编译之后,Xcode会自动生成Person的实体代码文件,并且文件不会显示在工程中,如果下图中右侧Codegen选择Manual/None,则Xcode就不会自动生成代码,我们可以自己手动生成。
![](https://img.haomeiwen.com/i3873004/f173f833442ef047.png)
- 手动生成实体类代码,选中CoreDataTest.xcdatamodeld文件,然后在Mac菜单栏中选择Editor,如下图所示。一路Next就可以了。
- 如果没有选择Manual/None,依然进行手动创建的话,则会与系统自动创建的文件发生冲突,这点需要注意。
- 你也可以不要选择Manual/None,直接使用系统创建好的NSManagedObject,同样会有4个文件,只是在工程中是看不到的。
![](https://img.haomeiwen.com/i3873004/2b736bc1c5123364.png)
Swift中手动创建出来的是这样2个文件
![](https://img.haomeiwen.com/i3873004/46c932fe20e13aff.png)
还要注意编程语言的选择,Swift或OC
![](https://img.haomeiwen.com/i3873004/03e56a90691514a8.png)
二、手动创建模型并实现AppDelegate中的代码
讲道理,这一节应该是Core Data堆栈的介绍与使用,不过由于之前的文章中已经有了,这里就不啰嗦了,我们直接上图和代码。
-
如下图所示,创建模型,我这里直接创建一个命名为Model的模型。
创建模型.png
-
创建Person表,两个属性name和age,注意右侧的
Codegen
我们这里选择Class Definition
,然后直接Command+B编译代码,Xcode会自动帮我们生成Person+CoreDataClass.swift
和Person+CoreDataProperties.swift
文件
![](https://img.haomeiwen.com/i3873004/020ae9298492d82f.png)
- 配置AppDelegate中的代码,首先导入CoreData头文件,然后懒加载
NSManagedObjectModel
注意modelURL中填写的是模型文件的名字,并且后缀填写
momd
import CoreData
lazy var managedObjectModel: NSManagedObjectModel = {
let modelURL = Bundle.main.url(forResource: "Model", withExtension: "momd")
let managedObjectModel = NSManagedObjectModel.init(contentsOf: modelURL!)
return managedObjectModel!
}()
- 懒加载持久化存储协调器
NSPersistentStoreCoordinator
sqliteURL
是sqlite文件的路径documentDir
是后面加载好了的Document路径
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
let persistentStoreCoordinator = NSPersistentStoreCoordinator.init(managedObjectModel: managedObjectModel)
let sqliteURL = documentDir.appendingPathComponent("Model.sqlite")
let options = [NSMigratePersistentStoresAutomaticallyOption : true, NSInferMappingModelAutomaticallyOption : true]
var failureReason = "There was an error creating or loading the application's saved data."
do {
try persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: sqliteURL, options: options)
} catch {
// Report any error we got.
var dict = [String: Any]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" as Any?
dict[NSLocalizedFailureReasonErrorKey] = failureReason as Any?
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 6666, userInfo: dict)
print("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
return persistentStoreCoordinator
}()
lazy var documentDir: URL = {
let documentDir = FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).first
return documentDir!
}()
- 懒加载
NSManagedObjectContext
lazy var context: NSManagedObjectContext = {
let context = NSManagedObjectContext.init(concurrencyType: NSManagedObjectContextConcurrencyType.mainQueueConcurrencyType)
context.persistentStoreCoordinator = persistentStoreCoordinator
return context
}()
三、创建并实现CoreDataManager
我一般是把数据存储方法封装到一个CoreDataManager中,这样在以后的使用中比较方便。当然,你也可以根据自己的需求灵活运用。
-
创建一个继承自
NSObject
的CoreDataManager.swfit
文件,并且import CoreData
创建CoreDataManager
-
实现
CoreDataManager
的单例,并且拿到AppDelegate中刚才懒加载的NSManagedObjectContext
swift中创建单例比较方便,直接
static let shared = CoreDataManager()
// 单例
static let shared = CoreDataManager()
// 拿到AppDelegate中创建好了的NSManagedObjectContext
lazy var context: NSManagedObjectContext = {
let context = ((UIApplication.shared.delegate) as! AppDelegate).context
return context
}()
- 实现更新数据的方法
除了查询数据,其余对数据进行增删改的时候,都别忘记调用这个方法,只有这个方法执行ok,才算增删改完成。
// 更新数据
private func saveContext() {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
- 增加数据(保存数据)
- 首先运用
NSEntityDescription
创建出person
- 然后为
person
赋值,最终调用saveContext()
方法保存数据
// 增加数据
func savePersonWith(name: String, age: Int16) {
let person = NSEntityDescription.insertNewObject(forEntityName: "Person", into: context) as! Person
person.name = name
person.age = age
saveContext()
}
- 获取所有数据
- 如果是通过系统自动生成的CoreData文件,
Person
会自带一个fetchRequest()
的方法,我们可以直接通过Person.fetchRequest()
的方式拿到person
的NSFetchRequest
对象- 然后通过
context
的fetch(fetchRequest)
方法拿到数据数组
// 获取所有数据
func getAllPerson() -> [Person] {
let fetchRequest: NSFetchRequest = Person.fetchRequest()
do {
let result = try context.fetch(fetchRequest)
return result
} catch {
fatalError();
}
}
- 获取特定条件的数据
- 可以利用
NSPredicate
来过滤出符合一定条件的数据- 而
NSFetchRequest
中有predicate
这样一个属性
// 根据姓名获取数据
func getPersonWith(name: String) -> [Person] {
let fetchRequest: NSFetchRequest = Person.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "name == %@", name)
do {
let result: [Person] = try context.fetch(fetchRequest)
return result
} catch {
fatalError();
}
}
- 修改数据
- 首先获取到想要修改的数据
- 然后循环修改就可以了
- 最后别忘记
save
// 根据姓名修改数据
func changePersonWith(name: String, newName: String, newAge: Int16) {
let fetchRequest: NSFetchRequest = Person.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "name == %@", name)
do {
// 拿到符合条件的所有数据
let result = try context.fetch(fetchRequest)
for person in result {
// 循环修改
person.name = newName
person.age = newAge
}
} catch {
fatalError();
}
saveContext()
}
- 根据条件删除数据
- 与修改数据一样,首先拿到符合删除条件的数据
- 循环调用
context
的delete()
方法就可以了- 最后别忘记
save
// 根据姓名删除数据
func deleteWith(name: String) {
let fetchRequest: NSFetchRequest = Person.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "name == %@", name)
do {
let result = try context.fetch(fetchRequest)
for person in result {
context.delete(person)
}
} catch {
fatalError();
}
saveContext()
}
- 删除所有数据
- 获取所有数据
- 循环删除
save
// 删除所有数据
func deleteAllPerson() {
// 这里直接调用上面获取所有数据的方法
let result = getAllPerson()
// 循环删除所有数据
for person in result {
context.delete(person)
}
saveContext()
}
后记
本文运用一个简单的示例来说明swift中如何使用CoreData
,更多用法或注意事项就不一一列举了。
本文Demo:https://github.com/remember17/CoreDataSwiftDemo
作者GitHub:https://github.com/remember17