一、iOS数据储存方式
二、简介CoreData数据存储
Core Data 是 iOS系统提供的数据存储方式,和传统的SQL相比:
-它无需写SQL语句
-允许开发者用面向对象的方式操作存储数据,它的实体类可以和table中的表结构对应
-可以通过谓词指定查询条件
-由于是苹果的亲儿子,在iOS系统上的性能很好,苹果也对它进行了多次优化
-苹果官方应用的数据存储几乎都使用 Core Data
项目中CoreData的嵌入
嵌入CoreData很简单,如果是还未创建工程,那么在创建工程时勾选上Use Core Data,工程就会自动生成一个与工程名字相同的.xcdatamodeld文件,以及在AppDelegate文件中自动生成相应代码。
如果已经创建了工程也不要紧,command + n找到Data Model并创建,创建的名字最好与工程名相同,否则可能会出现未知错误,不过作为例子我这里就随便起一个了。
创建完成后在文件目录中会多出一个.xcdatamodeld文件,现在先不忙管它,进入AppDelegate文件,import CoreData并添加相关代码,NSPersistentContainer(name:)中的参数必须与工程名一致,完事后如下:
import UIKit
import CoreData
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "TestCoreData")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
这样下来,CoreData就成功导入到工程中了。
但是这一坨代码写到AppDelegate里面不太雅观,出于“谁的事情谁来干”的原则,我们可以新建一个类,名为CoreDataStack.swift,把这一堆东西都移到新建的文件里面去。
CoreData的使用
CoreData为我们提供基本数据类型存储,可供选择的选项有14个,我这里就不一一列举,下文会有一张图能看到支持的类型。虽然只有14个选项,但是在我看来,CoreData是没有什么数据不能存储的,因为有个选项是Transformable,从字面意思就知道这个是可以转换的类型,从代码中用option可以查到它显示的类型是NSObject,这就很好办了,iOS中的所有对象都继承自NSObject,那我就可以将任意类型的数据转为NSObject再存储了,不过在转之前要注意:数据类型必须遵守NSCoding协议,这也是CoreData最大的诟病,需要自己实现协议中的encode和decode方法,如果模型有很多属性,就需要多写很多代码。
创建模型
找到之前的.xcdatamodeld文件并打开,选择Add Entity创建一个模型并取名,我这里取作SysUser,右侧第一栏Attributes就是模型的属性了,可以选择模型属性类型。
这是我们新建的一个SysUser的model:
简单的创建几个属性,因为CoreData不存在主键一说,所以自己设置一个id属性作为主键,这个id的唯一性由开发者自己保证。
增加数据
CoreData增加数据
首先要获得一个context(上下文对象),还记得我们上面说过的那个CoreDataStack.swift文件吗,它里面的代码应该是这样的:
import Foundation
import CoreData
class CoreDataStack: NSObject {
/**
创建单例
*/
static let shared = CoreDataStack()
lazy var documentDir: URL = {
let documentDir = FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).first
return documentDir!
}()
//获取上下文
lazy var context: NSManagedObjectContext = {
let context = NSManagedObjectContext.init(concurrencyType: NSManagedObjectContextConcurrencyType.mainQueueConcurrencyType)
context.persistentStoreCoordinator = persistentStoreCoordinator
return context
}()
// 存储数据
func saveContext() {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "LeavesVideo")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
lazy var managedObjectModel: NSManagedObjectModel = {
let modelURL = Bundle.main.url(forResource: "LeavesVideo", withExtension: "momd")
let managedObjectModel = NSManagedObjectModel.init(contentsOf: modelURL!)
return managedObjectModel!
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
let persistentStoreCoordinator = NSPersistentStoreCoordinator.init(managedObjectModel: managedObjectModel)
let sqliteURL = documentDir.appendingPathComponent("LeavesVideo.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
}()
}
这样我们就可以调用
class func getContext()->NSManagedObjectContext {
return CoreDataStack.shared.context
}
获取到上下文。
/**添加用户*/
class func insertUser(user:User){
let person = NSEntityDescription.insertNewObject(forEntityName: "SysUser", into: UserUtil.getContext()) as! SysUser
person.nickName = user.nickName
person.icon = user.icon
person.token = user.token
person.id = user.id
CoreDataStack.shared.saveContext()
}
查
/**获取用户*/
class func getCurrentUser()->SysUser{
do {
let results:[SysUser] = try UserUtil.getContext().fetch(SysUser.fatchUserRequest()) as! [SysUser]
return results[0]
} catch {
fatalError();
}
}
改
**更新用户的昵称*/
class func updateUserNickName(name:String){
do {
// 拿到符合条件的所有数据
let result:SysUser = try UserUtil.getContext().fetch(SysUser.fatchUserRequest())[0] as! SysUser
result.nickName = name
} catch {
fatalError();
}
CoreDataStack.shared.saveContext()
}
删
/**删除用户*/
class func deleteUser(){
//先查询数据是否存在
do {
let results:[SysUser] = try UserUtil.getContext().fetch(UserUtil.fatchUserRequest()) as! [SysUser]
if results.isEmpty == false{
// 删除所有数据
UserUtil.getContext().delete(result[0])
CoreDataStack.shared.saveContext()
}
} catch {
fatalError();
}
}