CoreData(二)

  • 參考書籍:CORE DATA by Tutorials
  • 默認有swift基礎。
  • 默認已閱讀上一篇內容。

親愛的們,上一篇我們簡單的講了Core Data的存儲以及讀取,我們已經說過了Core Data是對象圖形化管理模式,既然對象放在最前面,那么在Core Data中最正確的操作方式應該是使用對象和屬性來進行操作。
這一篇的主要內容:

  • 使用所有的Attributes的類型。
  • 使用對象來進行儲存以及讀取數據。
  • data model的檢驗限制功能。

(1)、使用所有的Attributes的類型
在這一篇中我們也用一個Demo來演示,Demo如圖所示:

已拖拽好控件

那塊綠色表示最喜歡的顏色。
那只斯派克表示頭像。
(一切從簡,以CoreData操作為核心。)
在name和age的輸入框輸入數據并且選擇好日期后,點擊Add按鈕會將name、年齡、最喜歡的顏色、生日、頭像全部保存起來。
點擊show按鈕會跳轉到下一界面,如圖:
自行創建一個新的文件并于此界面聯系起來,這里不演示如何操作,若有疑問請留言

在這個頁面中會顯示之前保存的數據。

在上一篇中我們知道在進行Core Data操作之前我們得先建立data model(數據模板),對此有問題的同學請參考[http://www.lxweimin.com/p/96e2b321449c]
這是我們建立的數據模型:

注意Entity名字以大寫開頭,Attributes名字以小寫開頭

Note:你應該發現了在.xcdatamodeld中Attributes(屬性)的Type(類型)中有三種整形:Integer 16, Integer 32 和 Integer 64。* 區別就在于占據多大內存,每種類型儲存數的大小都有一個范圍(當然范圍越大的占據內存越多):
Range for 16-bit integer: -32768 to 32767
Range for 32-bit integer: –2147483648 to 2147483647
Range for 64-bit integer: –9223372036854775808 to 9223372036854775807
在實際使用中應該根據需求來確定類型,比如說,在這里年齡使用Integer 16就完全夠用。

在Type有一個類型是“Binary Data”,這是一個萬能的類型,可以儲存一切你能想到的可以翻譯成二進制的東西,包括圖片、PDF、‘小電影’等等。
但是時間花銷和空間花銷仿佛是一個悖論,這里也是一樣,這種方便的操作方式,犧牲了很大的系統花銷。也就是說即使你只是想獲取他的名字,但是他也會把整個Binary(二進制)加載到緩存中,而這會十分影響用戶體驗。
十分幸運,Core Data早就想到這個問題了。選擇我們的Binary Data類型的屬性在右邊的屬性欄中你會發現一個名為Allows External Storage的選擇框,像這樣:


當你勾選了Allows External Storage以后,CoreData將給給每一個值都獨立儲存,并會生成一個URI作為入口 。

Note:Allows External Storage只有binary data類型擁有,并且,當你勾選了這個選擇框以后你就不能使用屬性來詢問Core Data。
(據說勾選了這個選擇框以后還容易導致數據丟失,未驗證。)

  • 存儲非標準類型數據
    有一些數據類型在Type一欄中并沒有出現,比如UIColor等。
    你會如何儲存UIColor?像這樣(e.g., red: 255, green: 101, blue: 155)?但是,事實上,你可以將UIColor轉化為data,然后使用Binary Data類型來進行儲存。當你需要讀取的時候再將data類型轉化為UIColor類型。
    Transformable Type
    Transformable類型可以儲存任何繼承自NSCoding的對象,任何你自定義的對象若是繼承自NSCoding也可以用Transformable類型來儲存。

(2)、使用對象來進行儲存以及讀取數據
上一篇中我們用key-value來存儲、讀取數據,look like this:

//Set the name
Test.setValue(name1, forKey: "name")
//Get the name
let name = Test.valueForKey("name")

你的確可以這樣操作。但是,這并不意味著你應該這樣操作。
key-value并沒有充分利用swift類型判斷和xcode 自動完成的功能。

最好的方法應該是給每一個Entity創建一個子類,每一個Entity的屬性都有自己的類型。
xcode可以自動給Core Data modal中的Entity生成一個類。像這樣操作:

選中.xcdatamodeled文件,然后點擊Editor->Create NSManagedObject Subclass-> 選中數據模板->選中要生成類的Entity,然后一直點next

在使用我們新創建的對象管理類來進行存醋以及讀取等操作之前,我們還有最后一步要做。選擇. xcdatamodeled選中Test Entity,打開右邊的屬性欄,將我們剛才創建的類和Entity連接起來,這看起來似乎和controller和類連接起來有些類似,不過有些不同的就是,這次我們得在類的名字之前添加上ProjectName.。那么在這里就是CoreDataTest2.Test*:

最新的xcode也許會在這一欄自動填寫,但經檢驗出錯,所以還是自己重新填一下

通過對象管理類來進行存儲讀取有以下兩個好處:

    1. 充分利用了xcode和編譯器。
  • 2.你可以重定義已經存在的方法。
    有些方法不被允許繼承

上一篇我們已經了解過,在進行Core Data操作時第一步就是獲取managedContext(‘暫存器’)。上一篇我們通過 application.delegate來獲取‘暫存器’,但是這樣操作看起來更像是一個全局變量。這一篇我用類與類之間的屬性傳遞的方法,來獲取這個‘暫存器’對象,打開AppDelegate.swift
插入以下代碼:
<pre><code>
func application(application:UIApplication,didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let viewController = self.window!.rootViewController as ViewController
viewController.managedContext = self.managedObjectContext
return true
}</code></pre>

打開ViewController.swift,添加頭文件“import CoreData”,添加一個全局變量。

    //這個變量就是我們的‘暫存器’,而這個暫存器在AppDelegate.swift中已經初始化。
    var managedContext:NSManagedObjectContext!

給addButton方法添加代碼
<pre><code> func insertSampleData() {
//1
let name = self.name.text
let age = self.age.text.toInt()!
let favoriteColor=self.favoriteColor.backgroundColor!
let birthday = self.birthday.date
let avatar = self.Avatar.image!
//2
let entity = NSEntityDescription.entityForName("Test", inManagedObjectContext: managedContext)
let TestObject = Test(entity: entity!, insertIntoManagedObjectContext: managedContext)
//3
TestObject.name=name
TestObject.age=age
TestObject.favoriteColor=favoriteColor
TestObject.birthday=birthday
let avatarData=UIImagePNGRepresentation(avatar)
TestObject.avatar=avatarData
//4
var error: NSError?
if !managedContext.save(&error) {
println("Could not save (error), (error!.userInfo)")
}

</code></pre>

解釋一下這一段代碼:

  • //1 獲取在屏幕中輸入的各種信息。
  • //2 新建一個Test對象TestObject,使用初始化方法
    init(entity: NSEntityDescription, insertIntoManagedObjectContext context: NSManagedObjectContext?)
  • //3 給新建的TestObject的變量賦值。
  • //4 保存‘暫存器’。
    是不是使用對象來進行保存方便許多,是的!

現在運行一下app,填寫信息(age一欄請填寫整數,否則出錯,這里只考慮CoreData相關操作),點擊add按鈕以后信息被儲存,點擊show按鈕以后跳轉到下一界面,但是并沒有進行任何操作,現在給showViewController添加代碼。

讀取數據
打開ShowViewController.swift,在viewDidLoad()中添加以下代碼。
<pre><code>
override func viewDidLoad() {
super.viewDidLoad()
//1
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
//2
let request = NSFetchRequest(entityName:"Test")
var error: NSError? = nil
var results = managedContext.executeFetchRequest(request, error: &error) as! [Test]!
//3
let TestObject=results[results.count-1]
let name = TestObject.name
let age = TestObject.age
let birthday = TestObject.birthday
let favoriteColor:UIColor = TestObject.favoriteColor as! UIColor
let avatar = UIImage(data: TestObject.avatar)
//4
self.Avatar=UIImageView(image: avatar)
self.name.text = name
self.age.text = "(age)"
//格式化輸出生日
var fmt=NSDateFormatter()
fmt.dateFormat = "yyyy-MM-dd"
let birthdayString = fmt.stringFromDate(birthday)
self.birthday.text = birthdayString
self.favoriteColor.backgroundColor = favoriteColor

}

</code></pre>

代碼解釋:

  • //1 獲取‘暫存器’。
  • //2 創建請求,發出請求并將結果轉化為Test數組。
  • //3 取出數組中最后一個Test,也就是我們在界面上只能顯示最后一個輸入信息,通過對象的屬性我們找到了之前輸入的信息。
  • //4 將取到的信息顯示在界面上,其中favoriteColor從Anyobject轉化為UIColor,Avatar從NSData轉化為UIImage。

好的,這個Demo基本就完成了,我們來運行一下吧:

別忘了點擊Add按鈕
成功顯示,Demo的確夠簡陋~~~

到了這一篇的最后部分了。
數據驗證:

有時候我們對數據的內容有所限制,比如說年齡不能是負的,在coredata中這種驗證并不用我們自己來寫代碼,我們的data model就有這樣的功能。

打開我們的data model,選中我們要驗證的屬性,點開右邊的屬性輔助欄,如下圖所示:

年齡不能小于0,記得打上邊上的√

在紅色框中我們可以限定最大值 和 最小值。

Note:當我們修改我們的data model以后在運行程序會發生錯誤,原因就是我們修改了我們的model,最簡單的解決方法就是把我們的模擬器reset一下。


對data model的任何修改都可能使之發生錯誤,這個時候不妨把這個按鈕按一下

好的,接下來我們監測下當輸入超出我們的限定之后發生了什么,還記得我們的保存時的error嗎,我們將輸入的年齡為-1,我們來看一下輸出。

error.userInfo輸出了剛才輸入的全部信息,包括錯誤信息

既然發生了error,個么問題來了,如何處理error?
<pre><code>
var error: NSError?
if !managedContext.save(&error) {
println("Could not save (error), (error!.userInfo)")
if error!.code == NSValidationNumberTooLargeError{
println("值過大")
}
if error!.code == NSValidationNumberTooLargeError {
println("值過小")
}
}
</code></pre>

  if error!.code == NSValidationNumberTooLargeError
  if error!.code == NSValidationNumberTooLargeError

這兩句判斷語句能準確的告訴我們到底是發生了什么錯誤,根據不同錯誤以及實際情況來進行處理,靈活機動。


這一篇內容大體就是這樣了,主要講了通過對象來進行存儲以及讀取,而這樣操作的好處就是更加方便,充分利用了swift以及xcode的特性,也不容易出錯。
源代碼已上傳Github:https://github.com/superxlx/CoreDataTest2

好了,在下一篇再見。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 國家電網公司企業標準(Q/GDW)- 面向對象的用電信息數據交換協議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 11,145評論 6 13
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,765評論 18 399
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,923評論 18 139
  • 1.Core Data classes NSManagedObjectModel:用來創建數據模型,存儲屬性和保存...
    xiaocheche閱讀 353評論 0 1
  • 這個世界總是有和你生活格格不入的“賤人們”,時間久了就只能說,不好意思,我對你零容忍。從開始進入我可愛的可敬的二流...
    x流氓先生閱讀 674評論 1 1