iOS開發過程中使用Core Data應避免的十個錯誤

發表於2014-02-20

rgregerg4196_140219191554_1

Core Data是蘋果針對Mac和iOS平臺開發的一個框架,主要用來儲存資料。對很多開發者來說,Core Data比較容易入手,但很難精通,如果沒有正確的學習方法,你將很難真正理解它,更不用說精通了。很多開發者常常在這方面犯一些錯誤,而這篇文章列出了開發者在iOS開發過程中使用Core Data常見的一些錯誤,並對如何避免這些錯誤進行了分析。

 
1.不瞭解關鍵術語

對於iOS開發者來說,會使用Core Data是一項必備技能。 沒有它,很多app都不會存在。當在網際網路上四處搜尋Core Data學習教程,你很容易被各種各樣的術語嚇倒。事實上大部分學習教程都首先假定你已經知道了這些術語,而如果你不瞭解這些術語,那將會陷入困惑中。所以首先要知道關鍵的術語。這裡有一個備忘單,可以用在學習Core Data的過程中,這份備忘單展示了關鍵的片語:
regerghreh4196_140219191747_1

在以後的學習過程中,你會遇到更多的術語,但這些是初學者需要了解的最基本的部分。

2.完全忽視Core Data

當一項技術以難學“聞名”時,你可能會忽略它,特別是當你時間不夠,急著把app做出來的時候。

Core Data儲存app資料的一個常見替代選擇是使用XML屬性列表,雖然屬性列表可以讓你今天的工作變得輕鬆,但它們也會隨後回過頭來咬你一口。無論何時你編輯屬性列表,發生的變化都是原子性的。這意味著即便是很小的更改要求,整個檔案都會被載入到記憶體中,然後在儲存的時候,整個檔案都會被寫回到硬碟。

隨著資料量的增長,app也會變得越來越慢。但是如果你基於SQLite資料庫使用Core Data時,這些效能問題就不會困擾你 。這樣可以保持低記憶體佔用,以保證app快速響應,並防止app因記憶體壓力過大而崩潰。本質上說,Core Data之所以比屬性類表更有擴充套件性的原因是它支援使用資料庫進行永續性儲存。可擴充套件性並不是Core Data的唯一優勢,使用關係把資料組織進實體結構才是其強大之處。比如,考慮使用以下實體來代表一個任務 :
regrehgerh4196_140219191814_1

該任務實體包含一個名稱和subtask_name屬性。當從任務實體中建立管理物件時,它將會有一個名稱和subtask_name屬性。

不依賴關係,這個資料模型僅支援一個subtask,現在考慮以下實體:
thrtjytjytk4196_140219191852_1

帶有雙箭頭的線表明Task entity可以對應多個Subtask entity關係,這意味著一個任務可以有多個子任務,更不必說涉及到的父任務也能通過逆關係被包含進來。這個靈活性不僅方便,更節省了資料庫的空間,因為父任務名稱僅僅只需儲存一次。如果你想要更進一步,讓任務有子任務的子任務,下一步該怎麼辦?思考下重新構建以下任務實體:
rgergerh4196_140219191911_1

模型現在支援無線深度的子任務,因為任務實體關聯的是其本身!Core Data的可擴充套件性和靈活性還只是其優勢中很少的一部分。Core Data並不僅僅利用關聯式資料庫的優勢,而且你不必寫任何SQL語句來使用它。Core Data替你承擔了責任,並且為你自動優化了生成的SQL語句。

我還沒有深入研究Core Data的其他價值方面,比如模型版本控制、遷移、驗證以及變更管理和iCloud同步等等。如果有任何值得你投入時間的iOS框架,那就是Core Data。


3. 不使用模型版本控制和遷移

如果你已經編輯了一個管理物件模型,你可能已經犯了以下錯誤:

“此前用來開啟store的模型不相容以前用來建立store的模型”

當你建立資料持久化儲存,它是基於一個特定的管理物件模型的。如果模型的結構發生了變化,那麼持久化儲存就必須更新以匹配。如果不這麼做,store將會是不相容的,並且不能開啟。如果使用者正使用的儲存是基於你的沒有使用版本控制的模型,那麼app註定會崩潰。

為了確保模型遷移過程正常進行,你需要確保你在編輯模型前非常小心地新增了模型版本。

附註:一些變化,比如屬性預設、有效性規則以及獲取請求模板都可以被簡化。

4.過多使用版本控制和遷移

一旦開發者瞭解到維持管理物件模型版本的簡易,一些開發者不免會過分使用。這會產生一個過分複雜化的版本歷史記錄,如果每次更改都新增版本,這隻會減緩模型的遷移。

在你釋出Core Data app到App Store之前,你可以忽略版本控制,並按你喜歡的那樣編輯模型。為避免“the store is incompatible”錯誤,可以簡單地從開發裝置上刪除app,並再次在Xcode中執行。使用更新的模型部署一個新的持久化儲存,就可以解決崩潰問題。一旦你把model version 1釋出到App Store,你所有的使用者將會有version 1的持久化儲存。從這一點上來說,如果更新模型則必須新增一個新版本。我們假定你的使用者正使用model version 1。當開發一個更新版的app,你已經新增了model versions 2, 3和4。使用以下小技巧可以減少版本歷史,而不用釋出model versions 2, 3,4…
刪除model 2的內容
複製model 4內容至model 2
設定model 2為當前model
刪除model 4

當然,你需要考慮model 1中的實體如何對映到更重要的model 2中,尤其在你沒有使用輕量級遷移時。更加詳細的關於model版本控制和遷移,可檢視“Learning Core Data for iOS”這一個完整章節。

5.把一切留在記憶體中

你主要關注功能和特性,所以你很容易忘記那些不那麼迷人的主題,比如保持低記憶體佔用。有些開發者會在進行效能測試前急匆匆地釋出應用,尤其是截止期限所迫的情況下。不過還好我們仍有一些措施幫你保持低記憶體佔用。

當你管理物件時,在記憶體方面可使用管理物件context。一旦你完成了管理物件,你應該通過呼叫以下NSManagedObjectContext例項方法之一來移除它們。
通過重置來從context中移除所有管理物件。
使用refreshObject:mergeChanges並傳入引數NO 從context中移除特定的物件。

使用以上任意一個方法可以確保未使用的物件沒有浪費空間。為了在context中提高物件數目的可見性,可記錄[[context registeredObjects] count]結果以方便在控制檯中除錯。

6.設計一個低質量的Managed Object Model

如果你儲存照片、音訊或者視訊,你在模型設計上要十分小心。記住關鍵的一點是當你把managed object帶入context時,你正把所有資料一併帶入記憶體中。例如,如果一個managed object帶有一個影象屬性,該屬性儲存了一張很大的圖片,同時一個表格檢視使用它來建立眾多實體物件並填充單元格, 那麼app效能就會受到影響。即時你使用一個獲得結果的控制器,你仍需要一次載入很多高分率的圖片,這個操作不會立刻執行。為了解決這一問題,持有大量物件的屬性應該被分裂進一個關聯實體。按照這個方法,大量物件可以被持久化儲存。如果你需要在table view中展示照片,你應該使用自動生成縮圖代替。

7.不提前載入資料 

當你把模型載入進一個更新的app時,要注意不要意外地載入一個基於舊模型的預設資料儲存。如果你這麼做了,那麼對一些使用者來說,可能會在執行應用的時候導致崩潰。這個威脅可以從根本上阻止開發者載入一個預設的資料儲存。

如果有預設資料包含在app中,那app就更容易學習和使用了。一個程式越容易使用,那麼使用者就越有可能繼續使用它。使用者使用一款應用的時間越長,那麼使用者傳播它的機會就越大,最後也會提升應用潛在的銷售情況。為了避免在提供預設資料的情況下出現的更新時崩潰現象,你需要一個好的測試策略。

另外,你也需要深刻、準確地理解你想把什麼樣的模型版本和儲存釋出到App Store。你應該部署一個未改變的App Store應用版本到你的裝置上,新增資料,然後徹底測試升級程式。

8.只使用單一的Contexts 

Core Data的實現至少需要一個context 在主執行緒上操作。使用者介面也需執行在主執行緒,因此任何減緩主執行緒的行為都會降低程式的響應能力。雖然使用一個context非常容易,但是效能問題會悄然出現,除非你的資料設定非常小。比如,如果你想要生成資料縮圖,或者匯入一些資料,app就會這些過程中出現阻塞現象。

自從iOS 5以後,管理多個context已經變得非常容易了。現在你可以配置一個context 層級,並在前臺和後臺執行一些contexts。通過配置後臺context作為前臺 context的父類,你就可以實現後臺儲存。通過配置後臺context作為前臺context的子類,你就可以像匯入物件一樣匯入context來自動更新使用者介面.

9.不理解iCloud Integration的侷限性

iOS 7釋出以後 ,Core Data整合iCloud的實現變得更加簡單。iCloud一個關鍵性的限制是它的資料被約束在一個iCloud賬戶中。由於iCloud賬戶是與使用者裝置的方方面面交錯在一起,所以分享iCloud賬戶是不切實際的,不推薦的。這意味著iCloud 不能被用來共享。比如,假定一位丈夫和妻子想要在同一個購物列表上列出物品,這一點當前對iCloud來說也是不可能的。

除了賬號限制,iCloud也不支援ordered relationships,也限制你的輕量級的model遷移。跳出這個圈子思考,如果你對app使用的收集分析統計比較感興趣,你可以考慮使用Backend-as-a-Service (BaaS)。

10.不考慮現有的客戶資料整合iCloud

在iOS 7中,iCloud整合Core Data已經容易了很多,很多開發者有信心在應用中支援它,此前用它來託管珍貴的使用者資料並不穩定。這導致了很多現有的app僅有本地儲存,比如我自己的‘Teamwork’ app。

iOS 7中iCloud重要的簡化之一是fallback store的引入,它允許在iCloud accounts和iCloud Documents和Data之間無縫過渡。使用者可以使用支援iCloud的app,即便他們沒有任何網路連線,並在有可用網路時把資料整合到iCloud中。

雖然這有點不可思議,基於iOS 7之前版本開發的 應用中,用於儲存使用者資料的本地儲存方案都應該被遺忘。

如果你僅開啟iCloud,那你將使用一個不同的儲存,並且你將需要把使用者的本地資料合併到iCloud。在你嘗試把使用者資料整合到iCloud之前,你需要檢查以下幾點:
使用者註冊了iCloud嗎?
使用者想要在app中使用iCloud嗎?
使用者希望把本地資料合併到iCloud嗎?

如果以上的答案中有一個“no”,那麼這個app應該能在未來處理不同的答案。如果你的答案是“yes”,那麼你需要管理使用者本地資料遷移到iCloud的程式。當使用者的多個裝置上存有本地資料時,事情就變得有趣了。如果是這樣,那你將需要考慮重複資料刪除策略了。

總結

如果說有一個iOS框架值得你投入時間,那就是Core Data。如果你對它感興趣,可以考慮我的新書–Learning Core Data for iOS。這是本基於iOS 7的書,帶你領略整個Core Data的教程。可在此檢視本書概要

相關文章