一、iOS數(shù)據(jù)儲存方式
二硕并、簡介CoreData數(shù)據(jù)存儲
Core Data 是 iOS系統(tǒng)提供的數(shù)據(jù)存儲方式纳猪,和傳統(tǒng)的SQL相比:
-它無需寫SQL語句
-允許開發(fā)者用面向?qū)ο蟮姆绞讲僮鞔鎯?shù)據(jù)陋葡,它的實(shí)體類可以和table中的表結(jié)構(gòu)對應(yīng)
-可以通過謂詞指定查詢條件
-由于是蘋果的親兒子棋傍,在iOS系統(tǒng)上的性能很好救拉,蘋果也對它進(jìn)行了多次優(yōu)化
-蘋果官方應(yīng)用的數(shù)據(jù)存儲幾乎都使用 Core Data
項(xiàng)目中CoreData的嵌入
嵌入CoreData很簡單,如果是還未創(chuàng)建工程瘫拣,那么在創(chuàng)建工程時(shí)勾選上Use Core Data亿絮,工程就會(huì)自動(dòng)生成一個(gè)與工程名字相同的.xcdatamodeld文件,以及在AppDelegate文件中自動(dòng)生成相應(yīng)代碼麸拄。
如果已經(jīng)創(chuàng)建了工程也不要緊派昧,command + n找到Data Model并創(chuàng)建,創(chuàng)建的名字最好與工程名相同拢切,否則可能會(huì)出現(xiàn)未知錯(cuò)誤蒂萎,不過作為例子我這里就隨便起一個(gè)了。
創(chuàng)建完成后在文件目錄中會(huì)多出一個(gè).xcdatamodeld文件淮椰,現(xiàn)在先不忙管它五慈,進(jìn)入AppDelegate文件,import CoreData并添加相關(guān)代碼,NSPersistentContainer(name:)中的參數(shù)必須與工程名一致,完事后如下:
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就成功導(dǎo)入到工程中了豺撑。
但是這一坨代碼寫到AppDelegate里面不太雅觀,出于“誰的事情誰來干”的原則黔牵,我們可以新建一個(gè)類,名為CoreDataStack.swift爷肝,把這一堆東西都移到新建的文件里面去猾浦。
CoreData的使用
CoreData為我們提供基本數(shù)據(jù)類型存儲,可供選擇的選項(xiàng)有14個(gè)灯抛,我這里就不一一列舉金赦,下文會(huì)有一張圖能看到支持的類型。雖然只有14個(gè)選項(xiàng)对嚼,但是在我看來夹抗,CoreData是沒有什么數(shù)據(jù)不能存儲的,因?yàn)橛袀€(gè)選項(xiàng)是Transformable纵竖,從字面意思就知道這個(gè)是可以轉(zhuǎn)換的類型漠烧,從代碼中用option可以查到它顯示的類型是NSObject杏愤,這就很好辦了,iOS中的所有對象都繼承自NSObject已脓,那我就可以將任意類型的數(shù)據(jù)轉(zhuǎn)為NSObject再存儲了珊楼,不過在轉(zhuǎn)之前要注意:數(shù)據(jù)類型必須遵守NSCoding協(xié)議,這也是CoreData最大的詬病度液,需要自己實(shí)現(xiàn)協(xié)議中的encode和decode方法厕宗,如果模型有很多屬性,就需要多寫很多代碼堕担。
創(chuàng)建模型
找到之前的.xcdatamodeld文件并打開已慢,選擇Add Entity創(chuàng)建一個(gè)模型并取名,我這里取作SysUser,右側(cè)第一欄Attributes就是模型的屬性了霹购,可以選擇模型屬性類型佑惠。
這是我們新建的一個(gè)SysUser的model:
簡單的創(chuàng)建幾個(gè)屬性,因?yàn)镃oreData不存在主鍵一說厕鹃,所以自己設(shè)置一個(gè)id屬性作為主鍵兢仰,這個(gè)id的唯一性由開發(fā)者自己保證。
增加數(shù)據(jù)
CoreData增加數(shù)據(jù)
首先要獲得一個(gè)context(上下文對象)剂碴,還記得我們上面說過的那個(gè)CoreDataStack.swift文件嗎把将,它里面的代碼應(yīng)該是這樣的:
import Foundation
import CoreData
class CoreDataStack: NSObject {
/**
創(chuàng)建單例
*/
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
}()
// 存儲數(shù)據(jù)
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
}()
}
這樣我們就可以調(diào)用
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 {
// 拿到符合條件的所有數(shù)據(jù)
let result:SysUser = try UserUtil.getContext().fetch(SysUser.fatchUserRequest())[0] as! SysUser
result.nickName = name
} catch {
fatalError();
}
CoreDataStack.shared.saveContext()
}
刪
/**刪除用戶*/
class func deleteUser(){
//先查詢數(shù)據(jù)是否存在
do {
let results:[SysUser] = try UserUtil.getContext().fetch(UserUtil.fatchUserRequest()) as! [SysUser]
if results.isEmpty == false{
// 刪除所有數(shù)據(jù)
UserUtil.getContext().delete(result[0])
CoreDataStack.shared.saveContext()
}
} catch {
fatalError();
}
}