認識CoreData - 基礎(chǔ)使用

該文章屬于劉小壯原創(chuàng),轉(zhuǎn)載請注明:劉小壯

配圖

第一篇文章中并沒有講CoreData的具體用法李破,只是對CoreData做了一個詳細的介紹番川,算是一個開始和總結(jié)吧。

這篇文章中會主要講CoreData的基礎(chǔ)使用吭产,以及在使用中需要注意的一些細節(jié)个从。因為文章中會插入代碼和圖片脉幢,內(nèi)容可能會比較多,比較考驗各位耐心嗦锐。

文章中如有疏漏或錯誤嫌松,還請各位及時提出,謝謝奕污!??`


創(chuàng)建自帶CoreData的工程

在新建一個項目時萎羔,可以勾選Use Core Data選項,這樣創(chuàng)建出來的工程系統(tǒng)會默認生成一些CoreData的代碼以及一個.xcdatamodeld后綴的模型文件碳默,模型文件默認以工程名開頭贾陷。這些代碼在AppDelegate類中,也就是代表可以在全局使用AppDelegate.h文件中聲明的CoreData方法和屬性嘱根。

系統(tǒng)默認生成的代碼是非常簡單的髓废,只是生成了基礎(chǔ)的托管對象模型、托管對象上下文儿子、持久化存儲調(diào)度器瓦哎,以及MOCsave方法。但是這些代碼已經(jīng)可以完成基礎(chǔ)的CoreData操作了柔逼。

系統(tǒng)生成代碼

這部分代碼不應(yīng)該放在AppDelegate中,尤其對于大型項目來說割岛,更應(yīng)該把這部分代碼單獨抽離出去愉适,放在專門的類或模塊來管理CoreData相關(guān)的邏輯。所以我一般不會通過這種方式創(chuàng)建CoreData弛饭,我一般都是新建一個“干凈”的項目赎离,然后自己往里面添加跛锌,這樣對于CoreData的完整使用流程掌握的也比較牢固。


CoreData模型文件的創(chuàng)建

構(gòu)建模型文件

使用CoreData的第一步是創(chuàng)建后綴為.xcdatamodeld的模型文件癌蓖,使用快捷鍵Command + N,選擇Core Data -> Data Model -> Next婚肆,完成模型文件的創(chuàng)建租副。

創(chuàng)建完成后可以看到模型文件左側(cè)列表,有三個選項Entities较性、Fetch Requests用僧、Configurations结胀,分別對應(yīng)著實體、請求模板责循、配置信息糟港。

模型文件

添加實體

現(xiàn)在可以通過長按左側(cè)列表下方的Add Entity按鈕,會彈出Add Entity院仿、Add Fetch Request秸抚、Add Configuration選項,可以添加實體歹垫、請求模板剥汤、配置信息。這里先選擇Add Entity來添加一個實體县钥,命名為Person秀姐。

添加Person實體后,會發(fā)現(xiàn)一個實體對應(yīng)著三部分內(nèi)容若贮,Attributes省有、RelationshipsFetched Properties谴麦,分別對應(yīng)著屬性蠢沿、關(guān)聯(lián)關(guān)系、獲取操作匾效。

空實體

現(xiàn)在對Person實體添加兩個屬性舷蟀,添加age屬性并設(shè)置typeInteger 16,添加name屬性并設(shè)置typeString面哼。

添加屬性
實體屬性類型

在模型文件的實體中野宜,參數(shù)類型和平時創(chuàng)建繼承自NSObject的模型類大體類似,但是還是有一些關(guān)于類型的說明魔策,下面簡單的列舉了一下匈子。

  • Undefined: 默認值,參與編譯會報錯
  • Integer 16: 整數(shù)闯袒,表示范圍 -32768 ~ 32767
  • Integer 32: 整數(shù)虎敦,表示范圍 -2147483648 ~ 2147483647
  • Integer 64: 整數(shù),表示范圍 –9223372036854775808 ~ 9223372036854775807
  • Float: 小數(shù)政敢,通過MAXFLOAT宏定義來看其徙,最大值用科學計數(shù)法表示是 0x1.fffffep+127f
  • Double: 小數(shù),小數(shù)位比Float更精確喷户,表示范圍更大
  • String: 字符串唾那,用NSString表示
  • Boolean: 布爾值,用NSNumber表示
  • Date: 時間摩骨,用NSDate表示
  • Binary Data: 二進制通贞,用NSData表示
  • Transformable: OC對象朗若,用id表示〔郑可以在創(chuàng)建托管對象類文件后哭懈,手動改為對應(yīng)的OC類名。使用的前提是茎用,這個OC對象必須遵守并實現(xiàn)NSCoding協(xié)議

添加實體關(guān)聯(lián)關(guān)系

創(chuàng)建兩個實體DepartmentEmployee遣总,并且在這兩個實體中分別添加一些屬性,下面將會根據(jù)這兩個實體來添加關(guān)聯(lián)關(guān)系轨功。

創(chuàng)建實體

Employee實體添加關(guān)系旭斥,在Relationships的位置點擊加號,添加一個關(guān)聯(lián)關(guān)系古涧。添加關(guān)系的名稱設(shè)為department垂券,類型設(shè)置為DepartmentInverse設(shè)置為employee(后面會講解這個inverse的作用)羡滑。

添加Relationships

選擇Department實體菇爪,點擊Relationships位置的加號,添加關(guān)聯(lián)關(guān)系柒昏。(需要注意的是凳宙,inverse需要設(shè)置好Relationships之后才能設(shè)置)

Department實體添加Relationships的操作和Employee都一樣,區(qū)別在于用紅圈標出的Type职祷,這里設(shè)置的To Many一對多的關(guān)系氏涩。這里默認是To One一對一,上面的Employee就是一對一的關(guān)系有梆。也就符合一個Department可以有多個Employee是尖,而Employee只能有一個Department的情況,這也是符合常理的泥耀。

添加Relationships

Relationships類似于SQLite的外鍵析砸,定義了在同一個模型中,實體與實體之間的關(guān)系爆袍。可以定義為對一關(guān)系或?qū)Χ嚓P(guān)系作郭,也可以定義單向或雙向的關(guān)系陨囊,根據(jù)需求來確定。如果是對多的關(guān)系夹攒,默認是使用NSSet集合來存儲模型蜘醋。

Inverse是兩個實體在Relationships中設(shè)置關(guān)聯(lián)關(guān)系后,通過設(shè)置inverse為對應(yīng)的實體咏尝,這樣可以從一個實體找到另一個實體压语,使兩個實體具有雙向的關(guān)聯(lián)關(guān)系啸罢。

Fetched Properties

在實體最下面,有一個Fetched Properties選項胎食,這個選項用的不多扰才,這里就不細講了。

Fetched Properties用于定義查詢操作厕怜,和NSFetchRequest功能相同衩匣。定義fetchedProperty對象后,可以通過NSManagedObjectModel類的fetchRequestFromTemplateWithName:substitutionVariables:方法或其他相關(guān)方法獲取這個fetchedProperty對象粥航。

fetched Property

獲取這個對象后琅捏,系統(tǒng)會默認將這個對象緩存到一個字典中,緩存之后也可以通過fetchedProperty字典獲取fetchedProperty對象递雀。

Data Model Inspector

選中一個實體后柄延,右側(cè)的側(cè)邊欄(Data Model Inspector)還有很多選項,這些選項可以對屬性進行配置缀程。根據(jù)不同的屬性類型搜吧,側(cè)邊欄的顯示也不太一樣,下面是一個String類型的屬性杠输。

Data Model Inspector
屬性設(shè)置
  • default Value: 設(shè)置默認值赎败,除了二進制不能設(shè)置,其他類型幾乎都能設(shè)置蠢甲。

  • optional: 在使用時是否可選僵刮,也可以理解為如果設(shè)置為NO,只要向MOC進行save操作鹦牛,這個屬性是否必須有值搞糕。否則MOC進行操作時會失敗并返回一個error,該選項默認為YES曼追。

  • transient: 設(shè)置當前屬性是否只存在于內(nèi)存窍仰,不被持久化到本地,如果設(shè)置為YES礼殊,這個屬性就不參與持久化操作驹吮,屬性的其他操作沒有區(qū)別。transient非常適合存儲一些在內(nèi)存中緩存的數(shù)據(jù)晶伦,例如存儲臨時數(shù)據(jù)碟狞,這些數(shù)據(jù)每次都是不同的,而且不需要進行本地持久化婚陪,所以可以聲明為transient的屬性族沃。

  • indexed: 設(shè)置當前屬性是否是索引。添加索引后可以有效的提升檢索操作的速度。但是對于刪除這樣的操作脆淹,刪除索引后其他地方還需要做出相應(yīng)的變化常空,所以速度會比較慢。

  • Validation: 通過Validation可以設(shè)置Max ValueMin Value盖溺,通過這兩個條件來約定數(shù)據(jù)漓糙,對數(shù)據(jù)的存儲進行一個驗證。數(shù)值類型都有相同的約定方式咐柜,而字符串則是約定長度兼蜈,date是約定時間。

  • Reg. Ex.(Regular Expression): 可以設(shè)置正則表達式拙友,用來驗證和控制數(shù)據(jù)为狸,不對數(shù)據(jù)自身產(chǎn)生影響。(只能應(yīng)用于String類型)

  • Allows External Storage: 當存儲二進制文件時遗契,如果遇到比較大的文件辐棒,是否存儲在存儲區(qū)之外。如果選擇YES牍蜂,存儲文件大小超過1MB的文件漾根,都會存儲在存儲區(qū)之外。否則大型文件存儲在存儲區(qū)內(nèi)鲫竞,會造成SQLite進行表操作時辐怕,效率受到影響。

Relationships設(shè)置
  • delete rule: 定義關(guān)聯(lián)屬性的刪除規(guī)則从绘。在當前對象和其他對象有關(guān)聯(lián)關(guān)系時寄疏,當前對象被刪除后與之關(guān)聯(lián)對象的反應(yīng)。這個參數(shù)有四個枚舉值僵井,代碼對應(yīng)著模型文件的相同選項陕截。

NSNoActionDeleteRule 刪除后沒有任何操作,也不會將關(guān)聯(lián)對象的關(guān)聯(lián)屬性指向nil批什。刪除后使用關(guān)聯(lián)對象的關(guān)聯(lián)屬性农曲,可能會導致其他問題。
NSNullifyDeleteRule 刪除后會將關(guān)聯(lián)對象的關(guān)聯(lián)屬性指向nil驻债,這是默認值乳规。
NSCascadeDeleteRule 刪除當前對象后,會將與之關(guān)聯(lián)的對象也一并刪除合呐。
NSDenyDeleteRule 在刪除當前對象時驯妄,如果當前對象還指向其他關(guān)聯(lián)對象,則當前對象不能被刪除合砂。

  • Type: 主要有兩種類型,To OneTo Many,表示當前關(guān)系是一對多還是一對一翩伪。
實體
  • Parent Entity: 可以在實體中創(chuàng)建繼承關(guān)系微猖,在一個實體的菜單欄中通過Parent Entity可以設(shè)置父實體,這樣就存在了實體的繼承關(guān)系缘屹,最后創(chuàng)建出來的托管模型類也是具有繼承關(guān)系的凛剥。注意繼承關(guān)系中屬性名不要相同。
    使用了這樣的繼承關(guān)系后轻姿,系統(tǒng)會將子類繼承父類的數(shù)據(jù)犁珠,存在父類的表中,所有繼承自同一父類的子類都會將父類部分存放在父類的表中互亮。這樣可能會導致父類的表中數(shù)據(jù)量過多犁享,造成性能問題。

Fetch Requests

在模型文件中Entities下面有一個Fetch Requests豹休,這個也是配置請求對象的炊昆。但是這個使用起來更加直觀,可以很容易的完成一些簡單的請求配置威根。相對于上面講到的Fetched Properties凤巨,這個還是更方便使用一些。

Fetch Requests

上面是對Employee實體的height屬性配置的Fetch Request洛搀,這里配置的height小于2米敢茁。配置之后可以通過NSManagedObjectModel類的fetchRequestTemplateForName:方法獲取這個請求對象,參數(shù)是這個請求配置的名稱留美,也就是EmployeeFR彰檬。

Editor Style

這是我認為CoreData最大的優(yōu)勢之一,可視化的模型文件結(jié)構(gòu)独榴∩妫可以很清楚的看到實體和屬性的關(guān)系,以及實體之間的對應(yīng)關(guān)系棺榔。

Editor Style

一個.xcdatamodeld模型文件的展示風格有兩種瓶堕,一種是列表的形式(Table),另一種是圖表的形式展示(Graph)症歇。

圖表看起來更加直觀郎笆,而圖表在操作上也有一些比Table更方便的地方。例如在Table的狀態(tài)下添加兩個實體的關(guān)聯(lián)關(guān)系忘晤,如果只做一次關(guān)聯(lián)操作宛蚓,默認是單向的關(guān)系。而在Graph的狀態(tài)下设塔,按住Control對兩個圖表進行連線凄吏,兩個實體的結(jié)果就是雙向關(guān)聯(lián)的關(guān)系。

手動創(chuàng)建實體

假設(shè)不使用.xcdatamodeld模型文件,全都是純代碼痕钢,怎么在項目里創(chuàng)建實體巴及亍?這樣的話就需要通過代碼創(chuàng)建實體描述任连、關(guān)聯(lián)描述等信息蚤吹,然后設(shè)置給NSManagedObjectModel對象。而使用模型文件的話一般都是通過NSManagedObjectModel對象來讀取文件随抠。

如果是純代碼的話裁着,蘋果更推薦使用KVC的方式存取值,然后所有托管對象都用NSManagedObject創(chuàng)建拱她。但是這樣存在的問題很多二驰,開發(fā)成本比較大、使用不方便等等椭懊。最大的問題就是寫屬性名的key字符串诸蚕,很容易出錯,而且這樣失去了CoreData原有的優(yōu)點氧猬。所以還是推薦使用.xcdatamodeld模型文件的開發(fā)方式背犯。

創(chuàng)建托管對象類文件

創(chuàng)建文件

創(chuàng)建實體后,就可以根據(jù)對應(yīng)的實體盅抚,生成開發(fā)中使用的基于NSManagedObject類的托管對象類文件漠魏。

還是按照上面DepartmentEmployee的例子,先創(chuàng)建一個Department實體妄均。因為Department實體有對多關(guān)系柱锹,生成托管對象類文件的關(guān)聯(lián)屬性不一樣,可以體現(xiàn)出和對一關(guān)系的區(qū)別丰包,所以使用Department實體生成文件禁熏。

點擊后綴名為.xcdatamodeld的模型文件,選擇XcodeEditor -> Create NSManagedObject Subclass -> 選擇模型文件 -> 選擇實體邑彪,生成Department實體對應(yīng)的托管對象類文件瞧毙。

生成的托管對象類文件

可以看到上面生成了四個文件,以實體名開頭的.h.m文件寄症,另外兩個是這個實體的Category文件宙彪。為什么生成Category文件?一會再說有巧,先打開類文件進去看看释漆。

Category

實體Category

可以看到類文件中有兩個Category,分別是CoreDataPropertiesCoreDataGeneratedAccessors篮迎。其中如果沒有設(shè)置對多關(guān)系的實體男图,只會有CoreDataProperties示姿,而設(shè)置了對多關(guān)系的實體系統(tǒng)會為其生成CoreDataGeneratedAccessors

CoreDataProperties中會生成實體中聲明的AttributesRelationships中的屬性享言,其中對多關(guān)系是用NSSet存儲的屬性峻凫,如果是對一的關(guān)系則是非集合的對象類型屬性。再看.m文件中览露,所有屬性都用@dynamic修飾,CoreData會在運行時動態(tài)為所有Category中的屬性生成實現(xiàn)代碼譬胎,所以這里用@dynamic修飾差牛。

對多屬性生成的CoreDataGeneratedAccessors,是系統(tǒng)自動生成管理對多屬性集合的方法堰乔,一般都是一個屬性對應(yīng)四個方法偏化,方法的實現(xiàn)也是在運行時動態(tài)實現(xiàn)的,方法都是用來操作集合對象的镐侯。

托管對象類文件

點擊系統(tǒng)生成的托管對象類文件侦讨,此類是繼承自NSManagedObject類的」斗可以看到里面非常干凈韵卤,沒有其他邏輯代碼。

根據(jù)蘋果的注釋代碼:Insert code here to declare functionality of your managed object subclass崇猫,提示應(yīng)該在這個文件中編寫此類相關(guān)的邏輯代碼沈条。這里就是編寫此類邏輯代碼的地方,當然也可以什么都不寫诅炉,看需求啦蜡歹。

任意類型屬性

實體支持創(chuàng)建任意繼承自NSObject類的屬性,例如項目中手動創(chuàng)建的類涕烧。項目中創(chuàng)建的類在下拉列表中并不會體現(xiàn)月而,可以在屬性類型選擇transformable類型,然后生成托管對象類文件的時候议纯,系統(tǒng)會將這個屬性聲明為id類型父款,在創(chuàng)建類文件后,可以直接手動更改這個屬性的類型為我們想要的類型痹扇。

對于手動設(shè)置的屬性有一個要求铛漓,屬性所屬的類必須是遵守NSCoding協(xié)議,因為這個屬性要被歸檔到本地鲫构。

標量類型

創(chuàng)建托管對象類文件時浓恶,實體屬性的類型無論是選擇的integer32還是float,只要是基礎(chǔ)數(shù)據(jù)類型结笨,最后創(chuàng)建出來的默認都是NSNumber類型的包晰,這是Xcode默認的湿镀。

如果需要生成的屬性類型是基礎(chǔ)數(shù)據(jù)類型,可以在創(chuàng)建文件時勾選Use scalar properties for primitive data types選項伐憾,這樣就告訴系統(tǒng)需要生成標量類型屬性勉痴,創(chuàng)建出來的屬性就是int64_tfloat這樣的基礎(chǔ)數(shù)據(jù)類型树肃。

標量類型

更新文件

當前模型對應(yīng)的實體發(fā)生改變后蒸矛,需要重新生成模型Category文件。生成步驟和上面一樣胸嘴,主要是替換Category文件雏掠,托管對象文件不會被替換。生成文件時不需要刪除劣像,直接替換文件乡话。


CoreData增刪改查

下面關(guān)于CoreData的相關(guān)操作,還是基于上面DepartmentEmployee的例子耳奕。并且引入了Company當做.xcdatamodeld模型文件绑青,前面兩個實體被包含在Company中。

先講講NSManagedObjectContext

iOS5之前創(chuàng)建NSManagedObjectContext對象時屋群,都是直接通過init方法來創(chuàng)建闸婴。iOS5之后蘋果更加推薦使用initWithConcurrencyType:方法來創(chuàng)建,在創(chuàng)建的時候指定當前是什么類型的并發(fā)隊列谓晌,初始化方法參數(shù)是一個枚舉值掠拳。這里簡單說說MOC,后面多線程部分還會涉及MOC多線程相關(guān)的東西纸肉。

NSManagedObjectContext初始化方法的枚舉值參數(shù)主要有三個類型:

  • NSConfinementConcurrencyType 如果使用init方法初始化上下文溺欧,默認就是這個并發(fā)類型。在iOS9之后已經(jīng)被蘋果廢棄柏肪,不建議用這個API姐刁,調(diào)用某些比較新的CoreDataAPI可能會導致崩潰。

  • NSPrivateQueueConcurrencyType 私有并發(fā)隊列類型烦味,操作都是在子線程中完成的聂使。

  • NSMainQueueConcurrencyType 主并發(fā)隊列類型,如果涉及到UI相關(guān)的操作谬俄,應(yīng)該考慮使用這個參數(shù)初始化上下文柏靶。

如果還使用init方法,可能會對后面推出的一些API不兼容溃论,導致多線程相關(guān)的錯誤屎蜓。例如下面的錯誤,因為如果沒有顯式的設(shè)置并發(fā)類型钥勋,默認是一個已經(jīng)棄用的NSConfinementConcurrencyType類型炬转,就會導致新推出的API發(fā)生不兼容的崩潰錯誤辆苔。

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'NSConfinementConcurrencyType context

創(chuàng)建MOC

下面是根據(jù)Company模型文件,創(chuàng)建了一個主隊列并發(fā)類型的MOC扼劈。

// 創(chuàng)建上下文對象驻啤,并發(fā)隊列設(shè)置為主隊列
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

// 創(chuàng)建托管對象模型,并使用Company.momd路徑當做初始化參數(shù)
NSURL *modelPath = [[NSBundle mainBundle] URLForResource:@"Company" withExtension:@"momd"];
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelPath];

// 創(chuàng)建持久化存儲調(diào)度器
NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];

// 創(chuàng)建并關(guān)聯(lián)SQLite數(shù)據(jù)庫文件荐吵,如果已經(jīng)存在則不會重復(fù)創(chuàng)建
NSString *dataPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
dataPath = [dataPath stringByAppendingFormat:@"/%@.sqlite", @"Company"];
[coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:dataPath] options:nil error:nil];

// 上下文對象設(shè)置屬性為持久化存儲器
context.persistentStoreCoordinator = coordinator;

這段代碼創(chuàng)建了一個MOC骑冗,我們從上往下看這段代碼。

momd文件

關(guān)于MOC的并發(fā)隊列類型上面已經(jīng)簡單說了先煎,MOC下面出現(xiàn)了momd的字樣性湿,這是什么東西躺孝?

momd文件

在創(chuàng)建后綴為.xcdatamodeld的模型文件后基跑,模型文件在編譯期將會被編譯為后綴為.momd的文件峦阁,存放在.app中隐解,也就是Main Bundle中王浴。在存在多個模型文件時嗡载,我們需要通過加載不同的.momd文件惩琉,來創(chuàng)建不同的NSManagedObjectModel對象闷供,每個NSManagedObjectModel對應(yīng)著不同的模型文件烟央。

NSManagedObjectModel類中包含了模型文件中的所有entitiesconfigurations歪脏、fetchRequests的描述疑俭。雖然.momd文件是支持存放在.app中的,其他人可以通過打開.app包看到這個文件婿失。但是這個文件是經(jīng)過編碼的钞艇,并不會知道這個.momd文件中的內(nèi)容,所以這個文件是非常安全的豪硅。通過NSManagedObjectModel獲取模型文件描述后哩照,來創(chuàng)建和關(guān)聯(lián)數(shù)據(jù)庫,并交給PSC管理懒浮。

如果不指定NSManagedObjectModel對應(yīng)哪個模型文件飘弧,直接使用init方法初始化NSManagedObjectModel類,系統(tǒng)會默認將所有模型文件的表都放在一個SQLite數(shù)據(jù)庫中砚著。所以需要使用mainBundle中的不同.momd文件次伶,對不同的NSManagedObjectModel進行初始化,這樣在創(chuàng)建數(shù)據(jù)庫時就會創(chuàng)建不同的數(shù)據(jù)庫文件稽穆。

持久化存儲調(diào)度器(PSC)

NSManagedObjectModel下面就是NSPersistentStoreCoordinator冠王,這個類在CoreData框架體系中起到了“中樞”的作用。對上層起到了提供簡單的調(diào)用接口秧骑,并向上層隱藏持久化實現(xiàn)邏輯版确。對下層起到了協(xié)調(diào)多個持久化存儲對象(NSPersistentStore)扣囊,使下層只需要專注持久化相關(guān)邏輯。

持久化存儲調(diào)度器

addPersistentStoreWithType: configuration: URL: options: error:方法是PSC創(chuàng)建并關(guān)聯(lián)數(shù)據(jù)庫的部分绒疗,關(guān)聯(lián)本地數(shù)據(jù)庫后會返回一個NSPersistentStore類型對象侵歇,這個對象負責具體持久化存儲的實現(xiàn)∠拍ⅲ可以看到這個方法是一個實例方法惕虑,也就是可以添加多個持久化存儲對象,并且多個持久化存儲對象都關(guān)聯(lián)一個PSC磨镶,這是允許的溃蔫,在上面的圖中也看到了這樣的結(jié)構(gòu)。但是這樣的需求并不多琳猫,而且管理起來比較麻煩伟叛,一般都不會這樣做。

PSC有四種可選的持久化存儲方案脐嫂,用得最多的是SQLite的方式统刮。其中BinaryXML這兩種方式,在進行數(shù)據(jù)操作時账千,需要將整個文件加載到內(nèi)存中侥蒙,這樣對內(nèi)存的消耗是很大的。

  • NSSQLiteStoreType : SQLite數(shù)據(jù)庫
  • NSXMLStoreType : XML文件
  • NSBinaryStoreType : 二進制文件
  • NSInMemoryStoreType : 直接存儲在內(nèi)存中

插入操作

// 創(chuàng)建托管對象匀奏,并指明創(chuàng)建的托管對象所屬實體名
Employee *emp = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:context];
emp.name = @"lxz";
emp.height = @1.7;
emp.brithday = [NSDate date];

// 通過上下文保存對象鞭衩,并在保存前判斷是否有更改
NSError *error = nil;
if (context.hasChanges) {
    [context save:&error];
}

// 錯誤處理
if (error) {
    NSLog(@"CoreData Insert Data Error : %@", error);
}   

通過NSEntityDescriptioninsert類方法,生成并返回一個Employee托管對象娃善,并將這個對象插入到指定的上下文中论衍。

MOC將操作的數(shù)據(jù)存放在緩存層,只有調(diào)用MOCsave方法后会放,才會真正對數(shù)據(jù)庫進行操作饲齐,否則這個對象只是存在內(nèi)存中,這樣做避免了頻繁的數(shù)據(jù)庫訪問咧最。

刪除操作

// 建立獲取數(shù)據(jù)的請求對象捂人,指明對Employee實體進行刪除操作
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];

// 創(chuàng)建謂詞對象,過濾出符合要求的對象矢沿,也就是要刪除的對象
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@", @"lxz"];
request.predicate = predicate;

// 執(zhí)行獲取操作滥搭,找到要刪除的對象
NSError *error = nil;
NSArray<Employee *> *employees = [context executeFetchRequest:request error:&error];

// 遍歷符合刪除要求的對象數(shù)組,執(zhí)行刪除操作
[employees enumerateObjectsUsingBlock:^(Employee * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    [context deleteObject:obj];
}];

// 保存上下文
if (context.hasChanges) {
    [context save:nil];
}

// 錯誤處理
if (error) {
    NSLog(@"CoreData Delete Data Error : %@", error);
}

首先獲取需要刪除的托管對象捣鲸,遍歷獲取的對象數(shù)組瑟匆,逐個刪除后調(diào)用MOCsave方法保存。

修改操作

// 建立獲取數(shù)據(jù)的請求對象栽惶,并指明操作的實體為Employee
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];

// 創(chuàng)建謂詞對象愁溜,設(shè)置過濾條件
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@", @"lxz"];
request.predicate = predicate;

// 執(zhí)行獲取請求疾嗅,獲取到符合要求的托管對象
NSError *error = nil;
NSArray<Employee *> *employees = [context executeFetchRequest:request error:&error];
[employees enumerateObjectsUsingBlock:^(Employee * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    obj.height = @3.f;
}];

// 將上面的修改進行存儲
if (context.hasChanges) {
    [context save:nil];
}

// 錯誤處理
if (error) {
    NSLog(@"CoreData Update Data Error : %@", error);
}

和上面一樣,首先獲取到需要更改的托管對象冕象,更改完成后調(diào)用MOCsave方法持久化到本地代承。

查找操作

// 建立獲取數(shù)據(jù)的請求對象,指明操作的實體為Employee
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];

// 執(zhí)行獲取操作渐扮,獲取所有Employee托管對象
NSError *error = nil;
NSArray<Employee *> *employees = [context executeFetchRequest:request error:&error];
[employees enumerateObjectsUsingBlock:^(Employee * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    NSLog(@"Employee Name : %@, Height : %@, Brithday : %@", obj.name, obj.height, obj.brithday);
}];

// 錯誤處理
if (error) {
    NSLog(@"CoreData Ergodic Data Error : %@", error);
}

查找操作最簡單粗暴论悴,因為是演示代碼,所以直接將所有Employee表中的托管對象加載出來墓律。在實際開發(fā)中肯定不會這樣做膀估,只需要加載需要的數(shù)據(jù)。后面還會講到一些更高級的操作耻讽,會涉及到獲取方面的東西察纯。

總結(jié)

CoreData中所有的托管對象被創(chuàng)建出來后,都是關(guān)聯(lián)著MOC對象的针肥。所以在對象進行任何操作后捐寥,都會被記錄在MOC中。在最后調(diào)用MOCsave方法后祖驱,MOC會將操作交給PSC去處理,PSC將會將這個存儲任務(wù)指派給NSPersistentStore對象瞒窒。

上面的增刪改查操作捺僻,看上去大體流程都差不多,都是一些最基礎(chǔ)的簡單操作崇裁,在下一篇文章中將會將一些比較復(fù)雜的操作匕坯。


好多同學都問我有Demo沒有,其實文章中貼出的代碼組合起來就是個Demo拔稳。后來想了想葛峻,還是給本系列文章配了一個簡單的Demo,方便大家運行調(diào)試巴比,后續(xù)會給所有博客的文章都加上Demo术奖。

Demo只是來輔助讀者更好的理解文章中的內(nèi)容,應(yīng)該博客結(jié)合Demo一起學習轻绞,只看Demo還是不能理解更深層的原理采记。Demo中幾乎每一行代碼都會有注釋,各位可以打斷點跟著Demo執(zhí)行流程走一遍政勃,看看各個階段變量的值唧龄。

Demo地址劉小壯的Github


這兩天更新了一下文章,將CoreData系列的六篇文章整合在一起奸远,做了一個PDF版的《CoreData Book》既棺,放在我Github上了讽挟。PDF上有文章目錄,方便閱讀丸冕。

如果你覺得不錯耽梅,請把PDF幫忙轉(zhuǎn)到其他群里,或者你的朋友晨仑,讓更多的人了解CoreData褐墅,衷心感謝!??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末洪己,一起剝皮案震驚了整個濱河市妥凳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌答捕,老刑警劉巖逝钥,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拱镐,居然都是意外死亡艘款,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門沃琅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哗咆,“玉大人,你說我怎么就攤上這事益眉∩渭恚” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵郭脂,是天一觀的道長年碘。 經(jīng)常有香客問我,道長展鸡,這世上最難降的妖魔是什么屿衅? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮莹弊,結(jié)果婚禮上涤久,老公的妹妹穿的比我還像新娘。我一直安慰自己忍弛,他們只是感情好拴竹,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著剧罩,像睡著了一般栓拜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天幕与,我揣著相機與錄音挑势,去河邊找鬼。 笑死啦鸣,一個胖子當著我的面吹牛潮饱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播诫给,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼香拉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了中狂?” 一聲冷哼從身側(cè)響起凫碌,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎胃榕,沒想到半個月后盛险,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡勋又,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年苦掘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片楔壤。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡鹤啡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蹲嚣,到底是詐尸還是另有隱情揉忘,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布端铛,位于F島的核電站,受9級特大地震影響疲眷,放射性物質(zhì)發(fā)生泄漏禾蚕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一狂丝、第九天 我趴在偏房一處隱蔽的房頂上張望换淆。 院中可真熱鬧,春花似錦几颜、人聲如沸倍试。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽县习。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間躁愿,已是汗流浹背叛本。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留彤钟,地道東北人来候。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像逸雹,于是被迫代替她去往敵國和親营搅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 該文章屬于劉小壯原創(chuàng)梆砸,轉(zhuǎn)載請注明:劉小壯[http://www.reibang.com/u/2de707c93d...
    劉小壯閱讀 19,793評論 17 149
  • 該文章屬于劉小壯原創(chuàng)转质,轉(zhuǎn)載請注明:劉小壯[http://www.reibang.com/u/2de707c93d...
    劉小壯閱讀 17,052評論 62 62
  • iOS CoreData介紹和使用(以及一些注意事項) 最近花了一點時間整理了一下CoreData,對于經(jīng)常使用S...
    Pocket閱讀 22,931評論 34 92
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理辫樱,服務(wù)發(fā)現(xiàn)峭拘,斷路器,智...
    卡卡羅2017閱讀 134,672評論 18 139
  • 基礎(chǔ) OC 是消息型語言狮暑,C 是函數(shù)調(diào)用型 消息型語言鸡挠,動態(tài)綁定(dynamic binding),運行時執(zhí)行的代...
    zhulang424閱讀 158評論 0 0