Swift

iOS项目中CoreData的使用

2018-11-17  本文已影响577人  栋柠柒

一、iOS数据储存方式


image

二、简介CoreData数据存储
Core Data 是 iOS系统提供的数据存储方式,和传统的SQL相比:
-它无需写SQL语句
-允许开发者用面向对象的方式操作存储数据,它的实体类可以和table中的表结构对应
-可以通过谓词指定查询条件
-由于是苹果的亲儿子,在iOS系统上的性能很好,苹果也对它进行了多次优化
-苹果官方应用的数据存储几乎都使用 Core Data

项目中CoreData的嵌入

嵌入CoreData很简单,如果是还未创建工程,那么在创建工程时勾选上Use Core Data,工程就会自动生成一个与工程名字相同的.xcdatamodeld文件,以及在AppDelegate文件中自动生成相应代码。


WX20181118-102146@2x.png

如果已经创建了工程也不要紧,command + n找到Data Model并创建,创建的名字最好与工程名相同,否则可能会出现未知错误,不过作为例子我这里就随便起一个了。


image

创建完成后在文件目录中会多出一个.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:


WX20181117-205847@2x.png

简单的创建几个属性,因为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();
        }
    }
上一篇下一篇

猜你喜欢

热点阅读