4-3 Core Data--數(shù)據(jù)模型和模型對象

本文我們將會(huì)更加深入探討Core Data 的models以及managed object的類 艺骂。本文絕不是對 Core Data 的簡單概述,而是在實(shí)際運(yùn)用中鮮為人知或不易記憶卻可以發(fā)揮奇效的那一部分的合集陨仅。如果你需要的是更詳細(xì)的概述,那么我推薦你去看“Apple’s Core Data Programming Guid”户魏。

數(shù)據(jù)模型

Core Data數(shù)據(jù)模型(儲(chǔ)存在 *.xcdatamodel 文件里)中定義了數(shù)據(jù)類型 (在 Core Data 里的“實(shí)體”中)饮戳。大多數(shù)情況下,我們更偏向通過 Xcode 的圖形界面去定義一個(gè)數(shù)據(jù)模型谆级,但同樣我們可以使用純代碼去完成這個(gè)工作烤礁。首先讼积,你需要?jiǎng)?chuàng)建一個(gè)NSManagenObjectModel對象,然后創(chuàng)建NSEntitiyDesciption對象來表示一組實(shí)體脚仔,該實(shí)體通過NSAttributeDescriptionNSRelationshipDescription對象來表示實(shí)體屬性和實(shí)體之間的關(guān)系勤众。雖然你幾乎不需要去處理這些事情,但是知道這些類總有好處鲤脏。

屬性 (Attributes)

一旦就創(chuàng)建了某個(gè)實(shí)體们颜,我們就需要去定義該實(shí)體的一些屬性。屬性定義是非常簡單的猎醇,但是接下來我們要深入的研究屬性的某些特性窥突。

默認(rèn)的/可選的

每個(gè)屬性可被定義成可選的或者非可選(必須)的。如果一個(gè)被變更的對象的非可選屬性沒有設(shè)置的話硫嘶,那么在存儲(chǔ)時(shí)將會(huì)失敗阻问。同時(shí),我們可以為每一個(gè)屬性設(shè)置默認(rèn)值沦疾。沒有人阻止我們使用一個(gè)可選的屬性并且給它賦一個(gè)默認(rèn)的值称近,但是當(dāng)你進(jìn)行深入思考的時(shí)候,你會(huì)發(fā)現(xiàn)這么做并沒有什么意義甚至引起混淆哮塞。所以刨秆,我們建議永遠(yuǎn)不要使用帶有默認(rèn)值的可選屬性。

瞬態(tài) Transient

另一個(gè)經(jīng)常被忽視的屬性的特性選項(xiàng)是它的transient忆畅。被聲明為transient的屬性除了不被持久化到本地之外衡未,其余所有行為都與正常屬性類似。這也意味著可以對它們進(jìn)行校驗(yàn)邻眷,撤銷管理眠屎,故障處理等操作。當(dāng)你將更復(fù)雜的數(shù)據(jù)模型邏輯映射到managed object subclasses的時(shí)候肆饶,transient屬性將會(huì)發(fā)揮出它的優(yōu)勢改衩。我們將會(huì)在后面繼續(xù)討論這個(gè)特性,以及我們更傾向于使用transient屬性而非實(shí)例變量的原因驯镊。

索引

如果你以前使用過關(guān)系數(shù)據(jù)庫葫督,那么你對索引應(yīng)該并不陌生。如果沒有板惑,你可以認(rèn)為屬性的索引可以提供一種大幅提高檢索速度的方法橄镜。但是有利有弊,索引在提高讀取速度的同時(shí)卻降低了寫入速度冯乘,因?yàn)槊慨?dāng)數(shù)據(jù)變更的時(shí)候洽胶,索引就需要進(jìn)行相應(yīng)的更新。

當(dāng)把一個(gè)屬性設(shè)置為indexed時(shí)裆馒,它將在SQLite中所對應(yīng)的表的列中建立索引姊氓。我們能夠?yàn)槿魏螌傩詣?chuàng)建索引丐怯,但是請留意對寫性能的潛在影響。Core Data 當(dāng)然也支持創(chuàng)建復(fù)合索引(在 entity 的 檢查器的 Indexs 部分中)翔横,就像那些橫跨了多個(gè)屬性的索引读跷。當(dāng)你在多屬性的場景下使用復(fù)合索引來獲取數(shù)據(jù)時(shí)可以對檢索效率進(jìn)行提升。Daniel 有一個(gè)使用復(fù)合索引獲取數(shù)據(jù)的例子:fetching data禾唁。

標(biāo)量類型

Core Data 支持包括整形效览、浮點(diǎn)型、布爾型在內(nèi)的許多常見數(shù)據(jù)類型荡短。但是數(shù)據(jù)模型編輯器默認(rèn)以 NSNumber 生成這些屬性并內(nèi)置于managed object子類中丐枉。這使得我們經(jīng)常會(huì)在程序代碼中用調(diào)用floatValue,boolValue肢预,integerValue等NSNumber的方法矛洞。

當(dāng)然,我們同樣可以直接設(shè)置這些屬性為想要的標(biāo)量類型烫映,如int64_t,float_t或是BOOL噩峦,它們一樣可以正常運(yùn)作锭沟。XCode甚至在生成NSManagedObject(原始數(shù)據(jù)類型使用標(biāo)量屬性)對話框內(nèi)有一個(gè)小選擇框可以為你進(jìn)行強(qiáng)類型匹配。 取而代之识补,不再會(huì)是:


而會(huì)用如下聲明替換:


這就是我們在 Core Data 中進(jìn)行獲取和保存標(biāo)量類型所需要做的全部族淮。在文檔中,仍然規(guī)定 Core Data 將不能自動(dòng)的為標(biāo)量生成存取方法凭涂,現(xiàn)在看來文檔似乎有點(diǎn)過時(shí)了了祝辣。

存儲(chǔ)其他類型對象

Core Data 并沒有約束我們只能對預(yù)定義類型進(jìn)行存儲(chǔ)。事實(shí)上切油,對于任何遵守NSCoding協(xié)議的對象甚至到任何包含了大量功能的結(jié)構(gòu)對象蝙斜,我們都可以對其進(jìn)行輕松的存儲(chǔ)。

我們可以通過使用transformable attributes來存儲(chǔ)遵守NSCoding協(xié)議的對象澎胡。我們需要做的僅僅是在下拉菜單中選擇 “Transformable” 選項(xiàng)孕荠。如果你生成了一個(gè)相應(yīng)的managed object subclasses,你就會(huì)看到一個(gè)類似如下的屬性聲明:


我們可以手動(dòng)將對象原有的id類型修改成任意我們想要儲(chǔ)存的類型來使編輯器進(jìn)行強(qiáng)類型檢查攻谁。然而在使用 transformable 屬性的時(shí)候我們會(huì)遇到一個(gè)陷阱:如果我們想使用默認(rèn)轉(zhuǎn)換器(最常用的)稚伍,我們必須不能為它指定名字。甚至指定默認(rèn)轉(zhuǎn)換器名字為其原始名字(NSKeyedUnarchiveFromDataTransformerName)都將會(huì)導(dǎo)致不好的事情戚宦。

不僅限于此个曙,我們還可以創(chuàng)建自定義的值轉(zhuǎn)換器并使用它們?nèi)ゴ鎯?chǔ)任意的對象類型。只要我們能夠把要存儲(chǔ)的東西轉(zhuǎn)化為可支持的基本類型受楼,我們就能存儲(chǔ)它垦搬。為了儲(chǔ)存比如結(jié)構(gòu)體這種不支持的非對象的類型祠挫,基本的解決方式是創(chuàng)建一個(gè)未定義類型的transient屬性和一個(gè)持久化的已支持類型的影子屬性。然后悼沿,重寫transient屬性的存取方法等舔,將值轉(zhuǎn)化為上述的持久化類型。這是很重要的糟趾,因?yàn)檫@些存取方法需要遵從KVC/KVO慌植,同時(shí)還需要考慮到 Core Data 原始存取方法。請閱讀蘋果指南中的non-standard persistent attributes(非標(biāo)準(zhǔn)的持久屬性)這一部分的自定義代碼义郑。

抓取屬性 (Fetched Properties)

在多個(gè)持久化存儲(chǔ)之間創(chuàng)建關(guān)系的時(shí)候我們經(jīng)常會(huì)用到fetched屬性蝶柿。由于使用多個(gè)持久化存儲(chǔ)本身已經(jīng)是非常不常見、且高級的案例非驮,因此fetched屬性幾乎也不會(huì)被使用交汤。

當(dāng)我們獲取一個(gè)抓取屬性的時(shí)候,Core Data 會(huì)在后端執(zhí)行一個(gè)抓取請求并且緩存抓取結(jié)果劫笙。我們可以直接在 Xcode 中數(shù)據(jù)模型編輯器里通過指定目標(biāo)實(shí)體類型和斷言來對抓去請求進(jìn)行配置芙扎。這里的斷言是動(dòng)態(tài)的而非靜態(tài)的,其通過 $FETCHSOURCE 和 $FETCHEDPROPERTY 兩個(gè)變量在程序運(yùn)行態(tài)進(jìn)行配置填大。更多細(xì)節(jié)可以參考蘋果官方文檔戒洼。

關(guān)系 (Relationships)

實(shí)體間的關(guān)系應(yīng)該總是被定義成雙向的。這給予了 Core Data 足夠的信息為我們?nèi)婀芾眍悎D允华。盡管定義雙向的關(guān)系不是一個(gè)硬性要求圈浇,但我還是強(qiáng)烈建議這么去做。

如果你對實(shí)體之間的關(guān)系很了解靴寂,你也能將實(shí)體定義成單向的關(guān)系磷蜀,Core Data 不會(huì)有任何警告。但是一旦這么做了百炬,你就必須承擔(dān)很多正常情況理應(yīng)由 Core Data 管理的一些職責(zé)褐隆,包括確認(rèn)圖形對象的一致性,變化跟蹤和撤銷管理收壕。舉一個(gè)簡單的例子妓灌,我們有“書”和“作者”兩個(gè)實(shí)體,并設(shè)置了一個(gè)書到作者的單項(xiàng)關(guān)系蜜宪。當(dāng)我們刪除了“作者”的時(shí)候虫埂,和這個(gè)“作者”有關(guān)聯(lián)的“書”將無法收到這個(gè)“作者”被刪除的消息。此后圃验,我們?nèi)耘f可以使用這本書“作者”的關(guān)系掉伏,只是我們將會(huì)得到一個(gè)指向空的錯(cuò)誤。

很明顯單向關(guān)系帶來的弊端絕對不會(huì)是你想要的。雙向關(guān)系化可以讓你擺脫這些不必要的麻煩斧散。

數(shù)據(jù)類型設(shè)計(jì)

在為 Core Data 設(shè)計(jì)數(shù)據(jù)模型的時(shí)候供常,一定要牢記 Core Data 不是一個(gè)關(guān)系數(shù)據(jù)庫。因此鸡捐,我們在設(shè)計(jì)數(shù)據(jù)模型的時(shí)候只需要著眼于數(shù)據(jù)將要如何組織和展示即可栈暇,而不是像設(shè)計(jì)數(shù)據(jù)庫表一樣來進(jìn)行設(shè)計(jì)。

在需要對某一數(shù)據(jù)進(jìn)行展示的時(shí)候避免大規(guī)模的抓取該數(shù)據(jù)的關(guān)系數(shù)據(jù)箍镜,從這一點(diǎn)看通常數(shù)據(jù)模型的非規(guī)范化是有其價(jià)值的源祈。再舉個(gè)例子,假如現(xiàn)有一個(gè)“作者”實(shí)體中有一個(gè)一對多的關(guān)系指向“書”實(shí)體的話色迂,如果我們只需要展示作者寫的書的數(shù)量的話香缺,再保存一個(gè)數(shù)字會(huì)是一個(gè)很好的做法。

這是因?yàn)樾僭O(shè)我們需要展示一張作者和其對應(yīng)作品數(shù)量的表图张。如果取得每個(gè)作者名下作品的數(shù)量這條數(shù)據(jù)只能通過統(tǒng)計(jì)作者實(shí)體關(guān)聯(lián)的書實(shí)體的數(shù)量來獲取,則每一個(gè)作者單元格中必須進(jìn)行一次抓取請求操作诈悍。這樣做性能不佳祸轮。我們可以使用relationshipKeyPathsForPrefetching對書對象進(jìn)行預(yù)抓取,但當(dāng)保存的書數(shù)據(jù)量大的時(shí)候写隶,這同樣無法達(dá)到理想狀態(tài)倔撞。所以,如果我們?yōu)槊總€(gè)作者添加一個(gè)屬性來管理書籍?dāng)?shù)量慕趴,那么,一切所需信息都將在請求抓取作者信息的時(shí)候一并獲得鄙陡。

當(dāng)然冕房,為保持冗余數(shù)據(jù)的同步,非規(guī)范化也會(huì)帶來額外的性能開銷趁矾。我們需要根據(jù)實(shí)際情況來權(quán)衡是否需要這么做耙册。有時(shí)這么做不會(huì)有什么感覺,但有時(shí)其帶來的麻煩會(huì)讓你頭疼不已毫捣。這樣做非常依賴于特定的數(shù)據(jù)模型详拙,比如應(yīng)用有沒有需要去與后臺(tái)交互,或者是否要在多個(gè)客戶端之間使用點(diǎn)對點(diǎn)的形式同步數(shù)據(jù)蔓同。

通常情況下饶辙,這個(gè)數(shù)據(jù)模型已經(jīng)被某個(gè)后臺(tái)服務(wù)定義過了,我們可能只需要將數(shù)據(jù)模型復(fù)制到應(yīng)用程序即可斑粱。然而弃揽,即使在這種情況下,我們?nèi)杂袡?quán)利在客戶端對數(shù)據(jù)模型進(jìn)行一些修改,就比如我們可以為后臺(tái)數(shù)據(jù)模型定義一個(gè)清晰的映射矿微。再拿“書”和“作者”舉例痕慢,僅在客戶端執(zhí)行向作者實(shí)體添加一個(gè)作品數(shù)量屬性的小操作以實(shí)現(xiàn)檢索性能的優(yōu)化而無需通知服務(wù)器。如果我們做了一些本地修改或從服務(wù)器接收到了新的數(shù)據(jù)涌矢,我們需要更新這些屬性并且保持其余的數(shù)據(jù)同步掖举。

實(shí)際情況往往復(fù)雜的多,但就像上面的簡單優(yōu)化娜庇,卻能緩解在處理標(biāo)準(zhǔn)關(guān)系數(shù)據(jù)庫數(shù)據(jù)模型的性能時(shí)的瓶頸問題塔次。

實(shí)體層級 vs 類層級

Managed object models 可以允許創(chuàng)建實(shí)體層級,即我們可以指定一個(gè)實(shí)體繼承另外一個(gè)實(shí)體思灌。雖然俺叭,實(shí)體間可以通用一些都有的屬性聽起來不錯(cuò),不過在實(shí)踐中我們幾乎不會(huì)這么去做泰偿。

這一切背后發(fā)生的事情其實(shí)是熄守,Core Data 將所有帶有相同父實(shí)體的實(shí)體存儲(chǔ)在同一張表中。這樣做會(huì)迅速的建成一個(gè)含有大量屬性的數(shù)據(jù)表耗跛,并使性能降低裕照。通常情況下,我們創(chuàng)建實(shí)體層級的目的僅僅是為了創(chuàng)建一個(gè)類層級调塌,從而可以在實(shí)體基類中實(shí)現(xiàn)代碼并分享到多個(gè)子類實(shí)體中晋南。當(dāng)然,我們還有更好的方法來實(shí)現(xiàn)這個(gè)需求羔砾。

實(shí)體層級與NSManagedObject父類層級是相互獨(dú)立的负间。換言之,我們不需要去為了已有的實(shí)體層級而去創(chuàng)建一個(gè)類層級姜凄。

讓我們繼續(xù)用“作者”和“書”舉例政溃。他們兩者間會(huì)有一些共有的字段,比如ID(identifier)态秧,創(chuàng)建時(shí)間(createdAt)董虱,修改時(shí)間(changedAt)。我們可以為這個(gè)例子構(gòu)建如下的結(jié)構(gòu):


然而申鱼,我們可以壓縮實(shí)體的層級關(guān)系而保持類的層級關(guān)系不變愤诱。


這個(gè)類可能會(huì)被這樣聲明:


這樣做的好處是我們能夠?qū)⒐餐拇a移動(dòng)到父類中,同時(shí)避免了將所有實(shí)體放到放到一個(gè)表中引起的性能消耗捐友。雖然我們在 Xcode 的管理對象生成器中無法根據(jù)實(shí)體層級來創(chuàng)建類層級淫半,但是花費(fèi)極少的代價(jià)去手動(dòng)的去創(chuàng)建管理對象類將會(huì)給我們巨大好處,具體我們會(huì)在下面介紹楚殿。

配置與抓取請求模板

所有使用過 Core Data 的人肯定都與數(shù)據(jù)模型的“實(shí)體-模型”方面的功能打過交道撮慨。但是數(shù)據(jù)模型還有兩個(gè)相對少見少用的領(lǐng)域:配置 (configurations) 和 抓取請求模板 (fetch request templates)竿痰。

配置用來定義是哪個(gè)實(shí)體需要保存在哪個(gè)持久化存儲(chǔ)。持久化存儲(chǔ)協(xié)調(diào)器使用addPersistentStoreWithType:configuration:URL:options:error:來添加持久化存儲(chǔ)砌溺,其中配置參數(shù)定義了需要映射的持久化存儲(chǔ)影涉。在目前所有的應(yīng)用場景中,我們只會(huì)使用一個(gè)持久化儲(chǔ)存规伐,因此不用考慮處理多個(gè)配置的情況蟹倾。當(dāng)創(chuàng)建好一個(gè)持久化存儲(chǔ)的時(shí)候默認(rèn)的配置就已經(jīng)為我們配置好了。其實(shí)還是有多存儲(chǔ)的極為少見的實(shí)例的猖闪,本話題的導(dǎo)入大數(shù)據(jù)集一文中對其進(jìn)行了概述鲜棠。

正如抓取請求模板的名字所暗示的那樣:預(yù)定義的抓取請求以managed object model的形式存儲(chǔ),需要時(shí)可以執(zhí)行fetchRequestFormTemplateWithName:substitutionVariables操作從而方便地使用培慌。我們可以使用 Xcode 中數(shù)據(jù)模型編輯器或者代碼來定義這些模板豁陆。雖然 Xcode 的編輯器還不能夠支持NSFetchRequest的所有功能。

老實(shí)說我曾經(jīng)有一段痛苦的經(jīng)歷去說服別人使用抓取請求模板吵护。其實(shí)一個(gè)好處是抓取請求的斷言將會(huì)被預(yù)先解析好盒音,從而當(dāng)你執(zhí)行一條新的抓取請求的時(shí)候該步驟不用每次執(zhí)行。雖然幾乎沒有什么聯(lián)系馅而,任何頻繁的抓取都會(huì)使我們陷入麻煩之中祥诽。假如你在找一個(gè)定義你抓取請求的地方(你不應(yīng)該將它們定義在視圖控制器中),也許考慮將它們儲(chǔ)存在于managed object model中將會(huì)是個(gè)不錯(cuò)的選擇瓮恭。

Managed Objects

任一使用 Core Data 的應(yīng)用其核心就是managed objects雄坪。managed objects依賴managed object context而存在并反映我們的數(shù)據(jù)。managed objects理應(yīng)在程序中至少穿透 model-controller 的壁壘屯蹦,甚至?xí)┩?controller-view 的壁壘维哈,而被分發(fā)。盡管后者頗具爭議但是我們可以更好的通過一個(gè)例子來進(jìn)行抽象理解:定義一個(gè)協(xié)議登澜,遵守該協(xié)議的對象可以被某個(gè)視圖使用笨农,或者是通過在視圖的類別中實(shí)現(xiàn)配置方法來橋接數(shù)據(jù)對象與特定的視圖之間的間隙。

不管怎么說我都不能將managed objects限定于數(shù)據(jù)層帖渠,當(dāng)我們想分發(fā)數(shù)據(jù)的時(shí)候,應(yīng)該將它們及時(shí)抓取出來并放入不同結(jié)構(gòu)中去竭宰。managed objects是 Core Data 應(yīng)用中的一等公民空郊,所以我們也要將它們用得適得其所。舉個(gè)例子切揭,managed objects應(yīng)該在兩個(gè)視圖控制器間進(jìn)行傳遞狞甚,并為它們提供所需要的數(shù)據(jù)。

為了獲取managed objects context我們經(jīng)常在代碼中看到如下代碼:


如果你已經(jīng)給視圖控制器傳遞了一個(gè)模型對象廓旬,可以直接通過對象來獲取上下文:


這么做移除了application delegate的隱性依賴并且增強(qiáng)了代碼可讀性以及更便于測試哼审。

使用 Managed object 子類

類似的,managed object的子類也應(yīng)當(dāng)這樣被使用。我們可以在這些類中實(shí)現(xiàn)自定義業(yè)務(wù)邏輯涩盾,驗(yàn)證邏輯和輔助方法十气,同時(shí)創(chuàng)建層級以便于剝離出共同的代碼放進(jìn)父類中。后者的實(shí)現(xiàn)非常簡單春霍,因?yàn)轭惖膶蛹壓蛯?shí)體層級的解耦合在上面已經(jīng)提過了砸西。

你可能想知道,當(dāng) Xcode 在重新生成文件的時(shí)候總是覆蓋它們址儒,那么如何在managed object子類中實(shí)現(xiàn)自定義代碼芹枷。其實(shí),這個(gè)答案十分簡單莲趣,不要使用 Xcode 生成它們即可鸳慈。如果你仔細(xì)想想,在這些類中被生成的代碼很瑣碎并且你自己也很容易能夠?qū)崿F(xiàn)喧伞,當(dāng)然你也可以只生成一次然后保證手動(dòng)更新就好走芋。因?yàn)樯傻闹皇且欢褜傩缘穆暶鳌?/p>

當(dāng)然還有一些其他的解決方案,如將自定義代碼放到類別中絮识,或者使用類似mogenerator這樣的工具绿聘。mogenerator 可以為每個(gè)實(shí)體和子類創(chuàng)建一個(gè)可以支持用戶代碼的基礎(chǔ)類。但是次舌,上面的所有解決方案都不能根據(jù)實(shí)體層級靈活的創(chuàng)建類層級熄攘。所以我們還是建議你手動(dòng)創(chuàng)建這些類,即使你需要自己去書寫幾行繁瑣的代碼彼念。

Managed Object 子類中的實(shí)例變量

當(dāng)我們開始使用managed object子類來實(shí)現(xiàn)業(yè)務(wù)邏輯的時(shí)候挪圾,我們可能會(huì)需要?jiǎng)?chuàng)建一些實(shí)例變量來緩存計(jì)算結(jié)果之類的東西。為了方便的達(dá)到這個(gè)目的逐沙,我們可以使用transient哲思。因?yàn)閙anaged object的生命周期與一般的對象有一點(diǎn)不同。Core Data 經(jīng)常會(huì)對那些不再需要的對象執(zhí)行faults操作吩案。如果我們要使用實(shí)例變量棚赔,就必須將其手動(dòng)加入進(jìn)程并且釋放這些實(shí)例變量。然而徘郭,當(dāng)我們換成transient屬性靠益,這一切都不再需要我們?nèi)プ隽恕?/p>

創(chuàng)建新對象

在模型類中可以加入一個(gè)類方法來將新的對象插入到 managed object 上下文中,這是在模型類中添加有用輔助方法的一個(gè)好例子残揉。Core Data 創(chuàng)建新對象的 API 并不是非常的直觀:


萬幸的是胧后,我們能夠輕易的在我們的子類中以一個(gè)優(yōu)雅的方式解決這個(gè)問題:


在,創(chuàng)建一個(gè)“書”對象就簡單得多抱环。


當(dāng)然壳快,如果我們將實(shí)際模型類從共同的父類中繼承下來纸巷,我們就應(yīng)當(dāng)將insertNewObjectIntoContext:和entityName這兩個(gè)方法移動(dòng)到父類中。然后每個(gè)子類里面就只需要去重寫entityName就可以了眶痰。

一對多關(guān)系賦值

如果你用 Xcode 生成了一個(gè)含有一對多關(guān)系的managed object子類的話瘤旨,系統(tǒng)將會(huì)為我們創(chuàng)建在這個(gè)關(guān)系中增刪對象的方法。


我們有一個(gè)更加優(yōu)雅的方法來替代這些賦值方法凛驮,尤其是在我們沒有生成managed object子類的情況下裆站。我們可以簡單的使用mutableSetValueForKey:方法獲取相關(guān)的可變對象的集合(或者對于有序關(guān)系的話,使用mutableOrderedSetValueForKey:)黔夭。這樣可以封裝成為一個(gè)更簡單的存取方法:


然后我們可以如同使用一般的集合那樣使用這個(gè)可變集合宏胯。Core Data 將會(huì)捕捉到這些變換,并且?guī)臀覀兲幚硎O碌氖虑椤?br>


驗(yàn)證

Core Data 支持多種數(shù)據(jù)驗(yàn)證的方式本姥。Xcode 的數(shù)據(jù)模型編輯器讓我們?yōu)閷傩灾贫ㄒ恍┗镜男枨蠹缗郏拖褚粋€(gè)字符串的最大和最小長度,或者是一對多關(guān)系中最多和最少的對象個(gè)數(shù)婚惫。除此之外氛赐,使用代碼我們可以做更多的事情。

文檔中“Managed Object Validation”一節(jié)對本主題有更加深入的介紹先舷。Core Data 通過實(shí)現(xiàn)validate:error:方法支持屬性層級驗(yàn)證艰管,以及通過validateForInsert:,validateForUpdate:,和validateForDelete:方法進(jìn)行屬性內(nèi)驗(yàn)證蒋川。驗(yàn)證將會(huì)在保存前自動(dòng)進(jìn)行牲芋,當(dāng)然我們也可以在屬性層使用validateValue:forKey:error:方法手動(dòng)觸發(fā)。

總結(jié)

Core Data 應(yīng)用依賴于數(shù)據(jù)模型與模型對象捺球。我們鼓勵(lì)大家不要去直接使用便利的封裝缸浦,而是去擁抱managed object子類和對象。當(dāng)使用 Core Data 的時(shí)候氮兵,值得非常注意的是要十分清楚發(fā)生了什么裂逐,否則的話一旦你的應(yīng)用變得復(fù)雜的時(shí)候,事情就會(huì)很糟糕了泣栈。

我們希望已闡述的幾個(gè)簡單的技術(shù)可以使你更容易的使用managed objects卜高。另外我們還初步了解了幾個(gè)非常高級的特性,以便大家在使用數(shù)據(jù)對象的時(shí)候?qū)ξ覀兡茏龅叫┦裁从袀€(gè)大致的概念南片。請謹(jǐn)慎地運(yùn)用這些技術(shù)篙悯,因?yàn)榈筋^來其實(shí)往往還是簡單才是王道。


翻譯作者:熊貓

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末铃绒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子螺捐,更是在濱河造成了極大的恐慌颠悬,老刑警劉巖矮燎,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異赔癌,居然都是意外死亡诞外,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門灾票,熙熙樓的掌柜王于貴愁眉苦臉地迎上來峡谊,“玉大人,你說我怎么就攤上這事刊苍〖让牵” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵正什,是天一觀的道長啥纸。 經(jīng)常有香客問我,道長婴氮,這世上最難降的妖魔是什么斯棒? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮主经,結(jié)果婚禮上荣暮,老公的妹妹穿的比我還像新娘。我一直安慰自己罩驻,他們只是感情好穗酥,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鉴腻,像睡著了一般迷扇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上爽哎,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天蜓席,我揣著相機(jī)與錄音,去河邊找鬼课锌。 笑死厨内,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的渺贤。 我是一名探鬼主播雏胃,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼志鞍!你這毒婦竟也來了瞭亮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤固棚,失蹤者是張志新(化名)和其女友劉穎统翩,沒想到半個(gè)月后仙蚜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡厂汗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年讲竿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了扳剿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蝶押。...
    茶點(diǎn)故事閱讀 40,117評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡狞悲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出衷畦,到底是詐尸還是另有隱情栗涂,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布霎匈,位于F島的核電站戴差,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏铛嘱。R本人自食惡果不足惜暖释,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望墨吓。 院中可真熱鬧球匕,春花似錦、人聲如沸帖烘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秘症。三九已至照卦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乡摹,已是汗流浹背役耕。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留聪廉,地道東北人瞬痘。 一個(gè)月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像板熊,于是被迫代替她去往敵國和親框全。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評論 2 355

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