《駕馭Core Data》 第三章 數據建模


本文由海水的味道編譯整理,請勿轉載,請勿用於商業用途。

   當前版本號:0.1.2

 第三數據建模 

Core Data棧配置好之后,接下來的工作就是設計對象圖,在Core Data框架中,對象圖被表示為NSManagedObjectModel。對象圖由若干個實體組成,實體被表示為NSEntityDescription。本章將圍繞實體設計的相關細節展開討論。本章也涉及到了常規的數據建模原則,因為這些原則也適用於創建實體。

   托管對象NSManagedObject和實體NSEntityDescription

托管對象和實體之間的關系就好比對象和類之間的關系。從概念上講,實體的構造與標准的面向對象編程類似。在Objective-C語言中,一個對象是一個NSObject類的實例,類描述(如isa指針)定義了對象的屬性。對象的類型不同表明它們是不同類的實例。每一個類都有不同的類描述。

Core Data中,一個NSManagedObject對象關聯一個實體描述(entity description),一個實體描述由一個NSEntityDescription對象表示。它提供了描述NSManagedObject對象的元數據,包括實體名,屬性名和關系名。NSManagedObject繼承自NSObject,通過Core Data提取到的對象,默認情況下都是NSManagedObject對象。這里讀者可能會疑問:為什么提取到的對象都是NSManagedObject類型呢?擁有不同屬性的實體對應的對象類型不是也應該不同嗎?原因是NSManagedObject的工作模式有點類似於字典:NSManagedObject對象可以存取任意的鍵-值對,即NSManagedObject對象會為所有的實體屬性保存相應的鍵-值對。

      常規的Objective-C包含屬性和方法,而一個實體只能包含屬性(關系也是屬性),如果你需要為實體添加自定義方法,你可以創建一個NSManagedObject子類。在子類中實現自定義方法。

將數據抽象為實體

設計數據模型的第一步是決定如何將你的數據划分為實體。通常這和在Web程序中使用數據庫表的原則類似。如果需要在數據庫中使用一張表,那就表示此處需要定義一個實體。

對於該規則的特例是連接表。在關系數據庫中,連接表被用來表示表與表之間的多對多關系。然而在Core Data中,這種表與表之間的連接關系Core Data會自動為你創建,你所需要做的就是在實體之間建立一個連接關系。Core Data會明白如何在持久化存儲文件中存儲關系:Core Data會在SQLite數據庫層創建一個相關的連接表,你永遠不用擔心這是如何實現的。

在提取數據過程中,一個傳統數據庫表列被轉化為一個實體的屬性。表行被轉化為實體的NSManagedObject實例。

屬性和關系

為了將一個模型數據映射為一個對象,我們一般通過繼承NSObject類創建一個模型類,然后將數據填充到模型類實例中。與此類似,為了讓Core Data能夠將從數據庫中提取的數據映射為對象,我們需要創建對應的實體,實體告訴NSPersistentStoreCoordinator映射對象的結構信息。實體的創建不需要編寫任何代碼,只需借助Xcode的數據模型設計器將模型類中的屬性相應的設置為實體的屬性。

當實體的屬性的類型是另一個實體,就需要使用關系。關系有兩種類型:一對一To One和一對多To Many。關系可以處理兩類問題。一類是當實體的屬性值類型是一個實體。比如Person實體的car屬性的值類型是Car實體,這個用實體屬性就無法表示,你需要通過一對一關系將Person和Car進行關聯。第二類問題是當實體的屬性需要引用多個實體實例。比如有一個客戶訂單類CustomerOrder,訂單類中有一個訂單項屬性orderItems,orderItems用來包含多個OrderItem對象,言下之意就是一個客戶訂單包含多個訂單項。因為Core Data沒有類似NSArray或NSSet這樣的集合屬性類型,所以你需要使用一對多關系將CustomerOrder與多個OrderItem關聯。在一對多關系中,無論“多”的一方指向何種類型,即使是NSString你也需要創建一個表示NSString對象的實體(比如一個CustomerComment實體包含了一個commentString屬性)。

如果你覺得為了一個NSString類型的屬性而創建一個新的實體沒這個必要。Core Data為此也提供了一個Binary Data屬性類型。你可以設置一個Binary Data類型的屬性,然后編寫一個將字符串數組歸檔為NSData對象並存儲為實體屬性的方法。當一個CustomerOrder實例從持久化存儲文件中被提取, NSData對象會被解檔為字符串數組。這種做法雖然可能會讓建模額外實體變得簡單,但這顯然會引入不必要的性能開銷。

數據標准化

數據標准化指的是為了最小化信息冗余以及讓查詢信息更簡單而將數據分離為相關聯的實體的過程。如果你要對之前例子中的CustomerOrder進行建模,那么將CustomerOrderCustomer中獨立出來會更有意義,而不是在每個訂單中都重復客戶的信息(比如Custom實體上有一個CustomerOrder屬性)。

如果一個客戶修改了他的名字,相對於需要修改該客戶所有的CustomerOrder對象上的客戶名信息,你只需要更新Customer對象的customerName屬性。這會更加快速簡單並且更少出錯。這也意味着從一個特殊的客戶對象中獲取他的所有訂單,僅需要向Customer對象查詢所有的CustomerOrder對象,而不是根據customerName搜索所有的CustomerOrder對象。

在傳統的數據庫設計中,范式是對標准化級別的衡量。對范式的一個完整討論已然超過了本書的范圍,但設計Web程序數據庫的原則也適用於Core Data使用。

如果你需要開發一個簡單的客戶訂單app,你可能決定使用三個單獨的實體:CustomerOrderOrderItemProduct。如圖3.1所示。

3.1 客戶訂單、訂單項、商品之間的關系

當一個客戶訂購了多個商品,一個CustomerOrder對象將被創建,並包含多個OrderItem對象表示已購買的商品。OrderItem對象存儲了商品購買時的價格,所以如果商品價格隨后發生了變化,CustomerOrder也會列出與訂單相關的正確價格。OrderItem沒有存儲商品名,因為這可以從OrderItemProduct對象之間的關系推導出來,使用key-path形式,查詢OrderItem對象的product.name

在圖3.1中,CustomerOrder沒有存儲總價,因為可能只需將選中的OrderItems的價格(乘以數量)相加起來[2]

如果這就是iOS app的數據模型設計,那么你可能考慮用一個頁面顯示最近的訂單,如圖3.2所示,每行顯示了一個OrderItem對象,訂單日期以及總價。

3.2 一個簡單的訂單頁面,列出了最近的客戶訂單

在計算表格視圖所有行的訂單總價時,你需要提取所有的OrderItem對象,然后對每個OrderItem執行purchasePrice * quantity的計算,最后將計算結果相加求和。該做法雖然可行,但在iOS設備上可能會遇到內存和性能問題。

如果在每個CustomerOrder對象中新增一個orderTotal用來保存訂單總價會更有意義。當某一個CustomerOrder已有1000條OrderItem,新增一個訂單項,你只需要將此訂單項的價格加到orderTotal上。為了顯示圖3.2所示的信息,你不再需要加載所有的OrderItem對象或執行任何計算。所以此方案可以獲得很好的性能。雖然這違反了傳統的正規化實踐,但這是一種以空間換時間的做法。

此外,通過緩存每個CustomerOrder對象的customerName,也會得到一點性能上的提升。因為這避免了只是為了顯示客戶姓名而提取相關Customer對象的開銷(注:假設CustomOrder實體有一個指向Customer實體的關系)。但是這需要為每種次序(按firstName或者lastName升序或降序)存儲重復的字符串。

當為Core Data項目設計數據模型時,規范化是必須的,這可以進一步優化app性能,減少數據的重復。然而適當的非規范化的重復數據,有時候反而會獲得更好的性能。個中利弊都需要你去權衡。

存儲二進制數據

如果你需要為一個NSManagedObject對象存儲二進制數據,比如一張圖片或一段音頻。你可以使用Binary Data屬性類型。同樣無論何時你使用這類數據,你都要警惕性能和內存問題。

考慮一個記錄姓名和地址的通訊錄iOS app。如果你想為每個聯系人存儲一張照片,你可能提出如圖3.3所示的實體設計。

3.3 一個通訊錄管理app的基本數據模型,數據模型包含照片屬性

如果你在頁面上每次只顯示一個聯系人,那么你不會遇到內存使用的問題。當你想顯示所有的聯系人,那么很明顯你需要從持久化存儲文件中提取所有聯系人對象。如果每個聯系人有512Kb的圖片附件,當你一次性加載所有聯系人,iOS設備的內存將很快被耗盡。

可以讓Core Data只提取指定的的屬性,將圖片屬性排除在外,除非在需要圖片的時候才進行提取。

另一種替代方案是給大的數據對象創建一個專門的實體,在主實體與數據實體之間使用一對一關系,如圖3.4所示。

3.4一個通訊錄管理app的基本數據模型,為圖片數據創建了一個單獨的實體

使用這種模型設計,你可以安全地一次從磁盤上加載所有的聯系人;當你提取這些對象,所有的圖片關系都處於惰性狀態,所以沒有圖片會被加載到內存。當你需要為聯系人顯示圖片時,一旦嘗試訪問圖片關系,圖片關系的惰性狀態就會被消除,接着圖片就從存儲區中被提取了。

本節主要介紹的術語和優化建議會貫穿本書其余的部分。

使用XCode的數據模型設計器

現在你已經了解了一些針對iOS Core Data實體設計的最佳實踐,下面介紹如何使用XCode內置的數據模型設計器創建NSManagedObject對象模型(也就是對象圖)。

為了遵循本章剩余部分的描述,現在使用Xcode創建一個新的數據模型文件。首先創建一個新的Empty Application模板項目,接着選擇File>New>New FileCommand+N快捷鍵),並從Core Data分組中選擇Data Model文件模板,如圖3.5所示。

3.5 新建Data Model文件的對話框

點擊Next,輸入模型標識名,選擇保存的磁盤位置。

當你創建了該文件后,空白的數據模型將會在數據模型設計器中打開。如圖3.6所示。

3.6 XCode數據模型設計器中的一個空白的數據模型文檔

XCode中,數據模型設計器有兩中編輯風格,TableGraph風格。

創建實體

為在XCode中創建實體,在窗口底欄點擊Add Entity按鈕。一個新的實體將被創建,在TableGraph編輯風格模式下,都會顯示這個新創建的實體。

作為一個例子,讓我們創建之前例子中的CustomerOrder實體。選擇View>Utilites>Data Model Inspector(按住Option+Command+3快捷鍵),打開數據模型檢視器。你將看到更詳細的配置選項,如圖3.7所示。

3.7 XCode中的數據模型檢視器

在數據模型檢視器中,將實體名修改為CustomerOrder

當命名實體時有許多要求和約定需要注意。比如Objective-C類名必須是以大寫字母開頭,不能包含空格,使用駝峰式大小寫。使用單數形式命名。

在右側的數據模型檢視器面板中,你也可以為實體指定Class Parent Entity,以及是否為Abstract Entity

Ø   實體的Class默認被設置為NSManagedObject,這意味着每一個從存儲區提取的對象將被實例化為NSManagedObject類實例。如果你需要創建了自定義的NSManagedObject類(比如你有一個Person實體,你想將該實體的NSManagedObject子類名設置為AWPerson),你就可以設置該值為你創建的自定義類。

Ø   雖然你不需要為你的實體名使用前綴,但是為你的自定義NSManagedObject類加上前綴是不錯的做法。比如實例化一個AWCustomerOrder類。

Ø   Parent Entity下拉菜單允許你指定一個繼承的父實體。與Objective-C類繼承中所有父類的屬性(對比:實體中的屬性和關系)會被子類繼承一樣。注意你無可以使用多繼承。

Ø   Abstract復選框被用於指定一個實體純粹是被用來用做另一個實體的父實體。對於這樣的實體,Core Data不會為其創建實際的NSManagedObject對象,它的存在僅是為了那些需要繼承抽象屬性的實體。

現在不用去管Class文本域中的內容,因為我們不打算在本章創建任何NSManagedObject的子類。Parent Entity也讓它保持默認值。繼承性將在第6章“使用NSManagedObject對象”中詳細討論。

實體檢視器也允許你配置一些其他的選項:

Ø   User Info區域用於為一個實體(不是實例)指定信息,信息將存儲在數據模型自身,而非屬性中。

Ø   Versioning區域用於配置需要版本控制的數據模型選項,這將在第8章“遷移與版本控制”中做更詳細的討論。

Ø   Entity Sync區域被用於使用桌面平台的同步服務,iOS平台不作使用。

創建屬性

現在在你的模型列表中,你已經有一個全新的實體。是時候對實體添加一些屬性了。

當在數據模型設計器中使用Table編輯器風格時,你將看到選中的實體屬性包含AttributesRelationships以及Fetched PropertiesAttributesRelationship兩項已經在之前的章節做過介紹。Fetched Properties是一個定義在實體上的屬性,它的值實際上是從另一個實體提取的。確保你的CustomerOrder實體被選中,點擊在窗口底欄的Add Attribute按鈕創建一個新的屬性,新的屬性會顯示在Attributes列表中。如果切換到Graph編輯風格,新的屬性會出現在實體的Attributes區域。如圖3.8所示。

3.8 XCode數據模型設計器中創建屬性

當你選中一個屬性,在窗口右側的數據模型檢視面板中你會看到有一些設置,而且這些設置項會根據你所設置的屬性類型不同而不同,大致分為以下幾類:  

Ø   Transient(瞬時)選項表示屬性不會存儲到持久化存儲文件中。Transient通常用在屬性的值是由其他屬性計算或合成而來(比如fullName屬性是根據Persion類實例的firstNamelastName拼接而來)。

Ø   Optional(可選)選項表示當前屬性的值允許為空。如果將屬性指定為Optional,那么即使屬性的值為空,實體的NSManagedObject實例也可被保存。如果該值是必選的(不選中Optional則為必選),如果屬性值為空,NSManagedObject對象上下文將拒絕保存這個屬性值不完整的NSManagedObject對象(當你嘗試並保存上下文,你將接收到一個NSError對象)。所有的屬性最初的狀態都是Optinal

Ø   Indexed選項表示底層的持久化存儲文件應該為該屬性生成一個索引;如果你使用基於多個屬性的查詢條件來提取對象,指定此類屬性為Indexed,可以大幅提高提取速度。

Ø   Reg.ExRegular Expression的縮寫,主要是用來驗證屬性值是否匹配特定的模式。此選項只對String類型有效。

Ø   Validation可以保證非法數據不被保存進持久化存儲文件中。數值屬性類型(Integer 16/32/64FloatDoubleDecimal)都有maximumminimum最大值最小值設定。你也可以對String類型設置最大長度和最小長度。或對Date類型設置日期范圍。不過最好的做法是當用戶向UITextField中輸入數據時就開始驗證數據,而非等到向上下文發送save消息才驗證數據。

Ø 除了TransformableBinary Data類型以外,Default適用於所有屬性類型。它被用來配置屬性的默認值。

Ø   Allows External Storage允許大尺寸的二進制數據可以保存在持久化存儲文件的外部。當你保存如照片,音頻或視頻時,建議是選中該選項, 這樣Core Data就會對大於1MB的數據保存在持久化存儲文件的外部。

將新的屬性名修改為orderDate。與實體名一樣,屬性的命名也有很多的要求和約定。屬性名不能以大寫字母開頭,不能包含空格,一般都是單數。對於Boolean類型屬性,你應該遵循Objective-C實例變量的約定,比如指定一個CustomerOrder對象是否已經發貨,那么應該命名屬性為shipped,而不是isShippedhasShipped等。

注意:

一些關鍵字不能被用作屬性名。在寫本書時,蘋果公司還沒有公布這類關鍵字列表。但是Xcode將生成一個編譯期警告。如果程序的行為古怪或者無法提取數據,那么可能屬性命名發生了沖突。一個常犯的錯誤是使用description作為屬性名,因為這和NSObject的同名方法相沖突。所以不要使用已經被NSObject或NSManagedObject方法使用的名稱。

接下來改變orderDate的類型為Date。當你改變了類型,另外的輸入域讓你指定約束和初始值,如圖3.9所示。

3.9 改變orderDate屬性的類型

Default文本域被用作指定屬性的初始值,無論何時,當一個新的NSManagedObject類實例被創建,該默認值將被自動設置。對於一個NSDate屬性,在自然語言字符基礎上這個域被用作設置一個日期,所以你可以指定一個明確的日期,比如“January 9, 2007 10:30 PST”或者一個模糊的日期參考,比如“yesterday atlunchtime”(沒錯,這樣可以!)

不幸的是,在寫本書時,任何你設置的默認值都會在編譯時作解釋。這對明確的日期是沒問題的,但自然語言字符串的表現將不會如你期望那樣。你可能認為設置初始值為“now”會讓orderData自動被設置為客戶訂單被創建的時間,但是事實是將會被設置為項目編譯時的時間。

注意:

如果你需要為新加入的NSManagedObject對象設置日期和時間,你可以在NSManagedObject子類的awakeFromInsert方法中設置,或者在插入一個對象后,手動設置日期。就像設置上一章標准模板項目中的timeStamp屬性。

Core Data屬性類型

Core Data屬性的可用類型如圖3.10所示。

3.10 Core Data可用的屬性類型

Undefined選項值是新創建的屬性的默認類型;如果屬性類型為undefined,項目將無法通過編譯。

Integer 16/32/64只表示整數,沒有小數點。所以如果10除以3,你將會得到3,而余數1會丟失。Integer 16/32/64之間唯一的區別是所表示的數值范圍不同。因為Core Data使用符號數,所以起始范圍是負數,而不是0

Integer 16 數值范圍:-32768~32767

Integer 32 數值范圍:-2147483648~2147483647

Integer 64 數值范圍:–9223372036854775808~9223372036854775807

標准整型數的最大值和最小值可以在stdint.h中找到。在任何類文件中輸入INT32_MAX,選中右擊,然后選擇Jump To Definition,你將看到許多最大值最小值定義。實體的屬性的類型是Integer 16/32/64,當創建此實體對應的NSManagedObject子類時,屬性最終的類型將會是NSNumber

DoubleFloat可以認為是有小數部分的整數。它們都是基於二進制數值系統,在CPU運算時很可能會發生舍入誤差。比如1/5,如果使用十進制數值系統,可以精確表示為0.2.但在二進制數值系統中,只能表示一個大概,在小數部分你會得到大量數字。所以不要使用IntegerDoubleFloat表示貨幣值。計算精度越高則越加趨於准確值,但內存占用也會越大。一個Float數使用32bit進行存儲,一個Double數使用64bit。它們都使用科學計數法進行存儲,所以一個數包含尾數和指數部分。

iOS中,最大的Float值是340282346638528859811704183484516925440.000000,最小的Float值是340282346638528859811704183484516925440.000000DoubleFloat都有一個符號位。而DoubleFloat的數值范圍更大。

當你決定該選擇Float還是Double時,想一下你的屬性是否真的需要超過Float提供的7位精度,如果不是,你應該選擇Float,因為它更加匹配64bitiPhone 5S底層處理器。除此之外,如果你想增加浮點數的計算速度而精度並沒有嚴格要求,Float也是最佳選擇。實體的屬性的類型是FloatDouble,當創建此實體對應的NSManagedObject子類時,屬性最終的類型將會是NSNumber

Decimal(十進制)是處理貨幣值和其他需要十進制場合下最佳選擇Decimal提供了優秀的計算精度,也消除了計算過程中的舍入誤差。因為CPU的本地數制是二進制,所以CPU在處理十進制數時,開銷會多一點。實體的屬性的類型是Decimal,當創建此實體對應的NSManagedObject子類時,屬性最終的類型將會是NSDecimalNumber 當你使用NSDecimalNumber執行計算時(如加減乘除計算),為了保證計算精度,你只能使用它提供的內建方法。更多關於NSDecimalNumber可參見這里

String類型和Objective-C中的NSString類似,用於保存字符數組。當生成實體對應的NSManagedObject子類時,String屬性被表示為NSString

Boolean數據類型被用於表示YES/NO值。當生成實體對應的NSManagedObject子類時,Boolean數據類型會被表示為NSNumber所以為了獲取布爾值,你需要想NSNumber對象發送boolValue消息。

Date類型是自解釋類型。用來存儲日期和時間。當生成實體對應的NSManagedObject子類時,Date類型會被表示為NSDate

Binary Data用來表示照片,音頻,或一些BLOB類型數據。當生成實體對應的NSManagedObject子類時,Binary Data數據類型會被表示為NSData

Transformable屬性類型用於存儲一個Objective-C對象。該屬性類型允許你存儲任何類的實例,比如你使用Transformable屬性表示UIColor當生成NSManagedObject子類時,Transformable類型會被表示為id對於id對象的保存和解檔需要使用一個NSValueTransformer的實例或子類的實例。由該類負責屬性值與NSData之間的轉換。但這也相當的簡單,尤其是當屬性值的類型已經實現了NSCoding協議,此時系統會自動提供一個默認的NSValueTransformer實例來完成歸檔和解檔。

創建另外的實體

為了在下一節中創建關系,還需創建一個OrderItem實體,實體包含以下屬性:

Ø   屬性名purchasePrice,類型Decimal,默認值為1.0

Ø   屬性名quantity,類型Integer16,默認值為1

接下來再次新增一個Product的新實體,包含以下屬性:

Ø   屬性名name,類型String

Ø   屬性名itemCost,類型Decimal,默認值為1.0

Graph編輯器模式下調整實體的位置,讓它們看上去如圖3.11那樣。

3.11 定義了多個實體的數據模型

創建關系

現在你已經定義了多個實體,是時候在它們之間加入關系了。

Xcode中,使用Table編輯器風格創建關系是最簡單的。選中某一個實體,點擊Relationships列表底欄的+號。通過在CustomerOrder實體上創建一個新的關系開始。針對關系設置的檢視器面板如圖3.12所示。

3.12 數據模型設計器中的關系檢視器面板

Name文本域中將關系命名為orderItems。對關系的命名約定和屬性的命名約定相似,但是對於一個一對多或多對多的關系,關系的命名應該為復數。一般來說,好的命名可以表明相關聯的實體名。在本例中,相關聯的實體是OrderItem

使用Destination下拉框設置關系指向的實體名,這里是OrderItem作為Destination值。Inverse下拉框用於設置一個定義在Destination上且回指當前CustomerOrder的關系名。以CustomerOrder的角度來看,Destination是從當前實體指出去,Inverse表示從其他實體指回來。因為你現在還沒有在OrderItem實體上定義任何關系,你現在可以跳過這一步。

一個CustomerOrder有許多的orderItems。所以選中To-Many Relationship。這將會啟用MinimumMaximum Count文本域,它被用來設置關系上的約束,比如一個客戶訂單必須有一個項目,但不超過50個。因為沒有對orderItems關系的約束,所以保留文本域的空白狀態。

檢視器中最后的下拉框被用來設置Delete Rule;當對象被刪除,該項設置發生在所有相關的被管理對象上。在第4章“基本的數據存儲與提取”會對這些選項值做更多的討論。

接下來選擇OrderItem實體,並創建一個叫做customerOrder關系。設置它的目標為CustomerOrder實體。因為任何一個訂單項目僅屬於一個客戶訂單,所以它不是to-many關系;所以關系名應是單數,並且To-Many Relationship復選框依然保留未選中狀態。

如果使用Graph編輯器風格顯示模型,你將發現兩個單獨的箭頭連接着CustomerOrderOrderItem實體,如圖3.13所示。

3.13 數據模型設計器中實體間的關系

注意到自CustomerOrderOrderItem實體的關系是一個雙向箭頭,這表明這是to-many關系。

現在你已經定義了兩個關系,你可以指定一個關系是另一個的反轉。點擊customerOrder關系,在Inverse下拉框中選擇相對關系orderItems。此時兩個帶箭頭的線段就變成了一個帶箭頭的線段,線段的兩頭都有箭頭。

指定反轉關系意味着當你在關系的一端設置了一個值,Core Data將處理相對的另一端。當你添加了一個訂單項目到客戶訂單中(比如,新增了一個orderItemorderItems關系),Core Data也會自動設置OrderItemcustomerOrder關系。

創建余下的關系

現在你已經知道如何在實體之間設置關系,為了完成我們的數據模型,在實體之間創建如圖3.14的關系。

3.14 數據模型設計器中正確設置在實體之間包含關系的數據模型

注意

Graph編輯器風格是為了在查看實體和關系時更直觀。工整的擺放實體還是將實體凌亂的堆在一起,實際上並沒有什么區別。

小結

你現在應該已經對Xcode中的數據模型設計器有了一個完整的認識。知道了如何創建實體和屬性,以及如何在實體間定義雙向關系。

你也已經了解了傳統的規范化原則並不總是適用於Core Data的模型;你經常因為性能和內存的原因需要非規范化你的數據模型。

在下一章,你將通過為iOS app創建新的被管理對象模型,把對Core Data模型的知識轉變為實踐。你將了解到如何使用Core Data框架創建新的NSManagedObject對象,並保存它們到持久化存儲文件。接着你將學習如何把它們提取出來,並顯示在表格視圖中。



[1]譯注:假設你將10個不同的商品加入購物車以方便比價。在最后結算時,你只勾選其中的三件商品,那么總的訂單總價就是將每件商品的數量乘以價格后各自相加。

[2]譯注:比如UIImageNSData之間的轉換。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM