Swift-CoreData高階

CoreData實(shí)現(xiàn)基礎(chǔ)的增刪改查其實(shí)非常簡(jiǎn)單,作為實(shí)際開(kāi)發(fā)你可能還需要了解CoreData版本遷移,CoreData實(shí)體對(duì)象之間的關(guān)聯(lián)關(guān)系,Context上下文實(shí)際操作過(guò)程中常見(jiàn)的誤操作,NSManagedObjectID的用途.簡(jiǎn)單歸類于高階,其實(shí)只是一些CoreData常用但易錯(cuò)的知識(shí)點(diǎn).

版本遷移

項(xiàng)目中開(kāi)發(fā)根據(jù)業(yè)務(wù)的發(fā)展,新增不同的表,也會(huì)對(duì)原有的表進(jìn)行擴(kuò)充,修改實(shí)體對(duì)象的同時(shí),我們需要對(duì)Model(.xcdatamodeld文件)進(jìn)行升級(jí),避免用戶在升級(jí)的時(shí)候發(fā)生崩潰.

① 新增版本號(hào):

FlyElephant.png

版本名字根據(jù)個(gè)人喜好和項(xiàng)目來(lái)命名


FlyElephant.png

② 版本號(hào)新增之后在Model下可以看到新增的版本


FlyElephant.png

③ 設(shè)置當(dāng)前版本號(hào)為最新的版本號(hào)


FlyElephant.png

④NSMigratePersistentStoresAutomaticallyOption設(shè)置為true表示CoreData會(huì)試著將低版本的持久化存儲(chǔ)區(qū)遷移到最新版本的模型文件,NSInferMappingModelAutomaticallyOption設(shè)置為true表示CoreData會(huì)試著以最為合理地方式自動(dòng)推斷出源模型文件的實(shí)體中,某個(gè)屬性到底對(duì)應(yīng)于目標(biāo)模型文件實(shí)體中的哪一個(gè)屬性.

 // 自動(dòng)升級(jí)選項(xiàng)設(shè)置
            let options = [
                NSMigratePersistentStoresAutomaticallyOption: true,
                NSInferMappingModelAutomaticallyOption: true
            ]
            
            try persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: self.storeURL as URL, options: options)

關(guān)聯(lián)關(guān)系

CoreData中實(shí)體關(guān)聯(lián)關(guān)系有三種,一對(duì)一,一對(duì)多,多對(duì)多,舉一個(gè)簡(jiǎn)單的例子Accoun和Order之間關(guān)系.一個(gè)賬戶有多個(gè)訂單.

FlyElephant.png

圖中的RelationShip有三個(gè)字段,關(guān)聯(lián)關(guān)系的名稱,對(duì)應(yīng)的Destination目標(biāo)表的名字,Inverse表示反向關(guān)系,如果沒(méi)有就是No Inverse.蘋果關(guān)系建議是為了保證數(shù)據(jù)之間的一致性,最好設(shè)置反向關(guān)系.每個(gè)Order對(duì)應(yīng)單一的用戶.


FlyElephant.png
FlyElephant.png

設(shè)置關(guān)聯(lián)之后還需要設(shè)置對(duì)應(yīng)的刪除規(guī)則(Delete Rule),蘋果默認(rèn)的關(guān)聯(lián)規(guī)則是Nullify:


FlyElephant.png

Deny 關(guān)系的Destination中只要有一個(gè)對(duì)象,就不能刪除,如果賬戶還有訂單,就不能刪除賬戶

Nullify 只在逆向關(guān)系Optional的時(shí)候有效,Accout 刪除之后,所有的Order中的account信息設(shè)置為nil

Cascade 刪除對(duì)象后,刪除destination所有對(duì)象.Account刪除之后,會(huì)刪除所有對(duì)應(yīng)的Order對(duì)象.

NoAction 刪除對(duì)象后,對(duì)Destination不做任何操作,在Destination中有大量對(duì)象的時(shí)候有用.

Context上下文

NSManagedObjectContext是連接對(duì)象和數(shù)據(jù)存儲(chǔ)之間的橋梁,Context有兩種并發(fā)類型,主線程和子線程并發(fā)類型.

public enum NSManagedObjectContextConcurrencyType : UInt {

    
    @available(iOS, introduced: 3.0, deprecated: 9.0, message: "Use another NSManagedObjectContextConcurrencyType")
    case confinementConcurrencyType

    case privateQueueConcurrencyType

    case mainQueueConcurrencyType
}

① 如果Context是nil,會(huì)遇到以下錯(cuò)誤:

+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name ‘Account’’

數(shù)據(jù)操作的時(shí)候盡量保證Context不為空.

② 設(shè)置關(guān)聯(lián)關(guān)系,新建立一個(gè)訂單,設(shè)置Order的關(guān)聯(lián)對(duì)象是Account:

do {

            let account:Account = Account.findAccountByName(name: "FlyElephant")!
            
            let privateContext:NSManagedObjectContext = try CoreDataManager.sharedManager.newPrivateQueueContextWithNewPSC()
            
            let order:Order = NSEntityDescription.insertNewObject(forEntityName: "Order", into: privateContext) as! Order
            order.orderName = "臺(tái)灣小零食--\(1)"
            order.orderNumber = Int32(100)
        
            order.account = account
            
            if privateContext.hasChanges {
                do {
                    print("保存成功")
                    try privateContext.save()
                } catch {
                    let nserror = error as NSError
                    fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
                }
            }
        }  catch {
            print(error)
        }

Account查詢:

static func findAccountByName(name:String) -> Account? {
        
        let context:NSManagedObjectContext = CoreDataManager.sharedManager.mainQueueContext
        
        let fetchRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Account")
        
        let predicate = NSPredicate.init(format: " accountName = %@", name)
        fetchRequest.predicate = predicate
        
        do {
            let searchResults = try context.fetch(fetchRequest)
            if searchResults.count > 0 {
                let account:Account = searchResults[0] as! Account
                return account
            } else {
                return nil
            }
        } catch  {
            print(error)
        }
        
        return nil
    }

但是這個(gè)時(shí)候會(huì)報(bào)錯(cuò):

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Illegal attempt to establish a relationship 'account' between objects in different contexts (source = <Order: 0x600000090ef0> (entity: Order; id: 0x60000022ffa0 <x-coredata:///Order/t0026FC90-22DC-459F-B59F-D0A225505AFE3> ; data: {
    account = nil;
    orderName = "\U53f0\U6e7e\U5c0f\U96f6\U98df--1";
    orderNumber = 100;
}) , destination = <Account: 0x600000090310> (entity: Account; id: 0xd000000000040000 <x-coredata://D472E515-79B3-469F-A842-73AE3A38D9F8/Account/p1> ; data: <fault>))'

Account和Order不在同一個(gè)Context上下文中,所以會(huì)出現(xiàn)錯(cuò)誤,可以在同一個(gè)上下文中進(jìn)行實(shí)體對(duì)象查詢:

do {

            let account:Account = Account.findAccountByName(name: "FlyElephant")!
            
            let privateContext:NSManagedObjectContext = try CoreDataManager.sharedManager.newPrivateQueueContextWithNewPSC()
            
            let order:Order = NSEntityDescription.insertNewObject(forEntityName: "Order", into: privateContext) as! Order
            order.orderName = "FlyElephant-臺(tái)灣小零食--\(1)"
            order.orderNumber = Int32(100)
        
            let accountInContext:Account = privateContext.object(with: account.objectID) as! Account
            order.account = accountInContext
            
            if privateContext.hasChanges {
                do {
                    print("保存成功")
                    try privateContext.save()
                } catch {
                    let nserror = error as NSError
                    fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
                }
            }
        }  catch {
            print(error)
        }

其中的objectID類型是NSManagedObjectID,并不是字符串類型:

open class NSManagedObjectID : NSObject, NSCopying {

    
    open var entity: NSEntityDescription { get } // entity for the object identified by an ID

    weak open var persistentStore: NSPersistentStore? { get } // persistent store that fetched the object identified by an ID

    
    open var isTemporaryID: Bool { get } // indicates whether or not this ID will be replaced later, such as after a save operation (temporary IDs are assigned to newly inserted objects and replaced with permanent IDs when an object is written to a persistent store); most IDs return NO

    
    open func uriRepresentation() -> URL // URI which provides an archivable reference to the object which this ID refers
}`</code></pre>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,545評(píng)論 19 139
  • 1 前言 CoreData不僅僅是數(shù)據(jù)庫(kù),而是蘋果封裝的一個(gè)更高級(jí)的數(shù)據(jù)持久化框架,SQLite只是其提供的一種數(shù)...
    RichardJieChen閱讀 3,138評(píng)論 2 2
  • 原創(chuàng) 2017-06-07 SwiftyJSON數(shù)據(jù)解析框架,據(jù)ThoughtWorks的周教練說(shuō),是由他們中國(guó)區(qū)...
    一根聰閱讀 14,900評(píng)論 0 12

友情鏈接更多精彩內(nèi)容