- 參考書籍:CORE DATA by Tutorials
- 默認(rèn)有swift基礎(chǔ)哆料。
- 默認(rèn)已閱讀上一篇內(nèi)容召噩。
親愛的們儡湾,上一篇我們簡單的講了Core Data的存儲以及讀取咐容,我們已經(jīng)說過了Core Data是對象圖形化管理模式,既然對象放在最前面庄撮,那么在Core Data中最正確的操作方式應(yīng)該是使用對象和屬性來進(jìn)行操作背捌。
這一篇的主要內(nèi)容:
- 使用所有的Attributes的類型。
- 使用對象來進(jìn)行儲存以及讀取數(shù)據(jù)洞斯。
- data model的檢驗限制功能毡庆。
(1)烙如、使用所有的Attributes的類型
在這一篇中我們也用一個Demo來演示么抗,Demo如圖所示:
那塊綠色表示最喜歡的顏色。
那只斯派克表示頭像厅翔。
(一切從簡,以CoreData操作為核心搀突。)
在name和age的輸入框輸入數(shù)據(jù)并且選擇好日期后刀闷,點擊Add按鈕會將name、年齡、最喜歡的顏色甸昏、生日顽分、頭像全部保存起來。
點擊show按鈕會跳轉(zhuǎn)到下一界面施蜜,如圖:
在這個頁面中會顯示之前保存的數(shù)據(jù)翻默。
在上一篇中我們知道在進(jìn)行Core Data操作之前我們得先建立data model(數(shù)據(jù)模板)缸沃,對此有問題的同學(xué)請參考[http://www.reibang.com/p/96e2b321449c]
這是我們建立的數(shù)據(jù)模型:
Note:你應(yīng)該發(fā)現(xiàn)了在.xcdatamodeld中Attributes(屬性)的Type(類型)中有三種整形:Integer 16, Integer 32 和 Integer 64修械。* 區(qū)別就在于占據(jù)多大內(nèi)存趾牧,每種類型儲存數(shù)的大小都有一個范圍(當(dāng)然范圍越大的占據(jù)內(nèi)存越多):
Range for 16-bit integer: -32768 to 32767
Range for 32-bit integer: –2147483648 to 2147483647
Range for 64-bit integer: –9223372036854775808 to 9223372036854775807
在實際使用中應(yīng)該根據(jù)需求來確定類型,比如說肯污,在這里年齡使用Integer 16就完全夠用腰根。
在Type有一個類型是“Binary Data”蔑歌,這是一個萬能的類型,可以儲存一切你能想到的可以翻譯成二進(jìn)制的東西,包括圖片靠闭、PDF、‘小電影’等等揭北。
但是時間花銷和空間花銷仿佛是一個悖論寨辩,這里也是一樣,這種方便的操作方式权逗,犧牲了很大的系統(tǒng)花銷美尸。也就是說即使你只是想獲取他的名字,但是他也會把整個Binary(二進(jìn)制)加載到緩存中斟薇,而這會十分影響用戶體驗师坎。
十分幸運,Core Data早就想到這個問題了堪滨。選擇我們的Binary Data類型的屬性在右邊的屬性欄中你會發(fā)現(xiàn)一個名為Allows External Storage的選擇框胯陋,像這樣:
當(dāng)你勾選了Allows External Storage以后,CoreData將給給每一個值都獨立儲存袱箱,并會生成一個URI作為入口 遏乔。
Note:Allows External Storage只有binary data類型擁有,并且发笔,當(dāng)你勾選了這個選擇框以后你就不能使用屬性來詢問Core Data盟萨。
(據(jù)說勾選了這個選擇框以后還容易導(dǎo)致數(shù)據(jù)丟失,未驗證了讨。)
-
存儲非標(biāo)準(zhǔn)類型數(shù)據(jù)
有一些數(shù)據(jù)類型在Type一欄中并沒有出現(xiàn)捻激,比如UIColor等制轰。
你會如何儲存UIColor?像這樣(e.g., red: 255, green: 101, blue: 155)胞谭?但是垃杖,事實上,你可以將UIColor轉(zhuǎn)化為data丈屹,然后使用Binary Data類型來進(jìn)行儲存调俘。當(dāng)你需要讀取的時候再將data類型轉(zhuǎn)化為UIColor類型。
Transformable Type
Transformable類型可以儲存任何繼承自NSCoding的對象旺垒,任何你自定義的對象若是繼承自NSCoding也可以用Transformable類型來儲存彩库。
(2)、使用對象來進(jìn)行儲存以及讀取數(shù)據(jù)
上一篇中我們用key-value來存儲袖牙、讀取數(shù)據(jù)侧巨,look like this:
//Set the name
Test.setValue(name1, forKey: "name")
//Get the name
let name = Test.valueForKey("name")
你的確可以這樣操作。但是鞭达,這并不意味著你應(yīng)該這樣操作司忱。
key-value并沒有充分利用swift類型判斷和xcode 自動完成的功能。
最好的方法應(yīng)該是給每一個Entity創(chuàng)建一個子類畴蹭,每一個Entity的屬性都有自己的類型坦仍。
xcode可以自動給Core Data modal中的Entity生成一個類。像這樣操作:
選中.xcdatamodeled文件叨襟,然后點擊Editor->Create NSManagedObject Subclass-> 選中數(shù)據(jù)模板->選中要生成類的Entity繁扎,然后一直點next
在使用我們新創(chuàng)建的對象管理類來進(jìn)行存醋以及讀取等操作之前,我們還有最后一步要做糊闽。選擇. xcdatamodeled選中Test Entity梳玫,打開右邊的屬性欄,將我們剛才創(chuàng)建的類和Entity連接起來右犹,這看起來似乎和controller和類連接起來有些類似提澎,不過有些不同的就是,這次我們得在類的名字之前添加上ProjectName.念链。那么在這里就是CoreDataTest2.Test*:
通過對象管理類來進(jìn)行存儲讀取有以下兩個好處:
- 充分利用了xcode和編譯器掂墓。
- 2.你可以重定義已經(jīng)存在的方法谦纱。
有些方法不被允許繼承
上一篇我們已經(jīng)了解過,在進(jìn)行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中已經(jīng)初始化。
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 保存‘暫存器’力崇。
是不是使用對象來進(jìn)行保存方便許多斗塘,是的!
現(xiàn)在運行一下app亮靴,填寫信息(age一欄請?zhí)顚懻麛?shù)馍盟,否則出錯,這里只考慮CoreData相關(guān)操作)茧吊,點擊add按鈕以后信息被儲存贞岭,點擊show按鈕以后跳轉(zhuǎn)到下一界面,但是并沒有進(jìn)行任何操作搓侄,現(xiàn)在給showViewController添加代碼瞄桨。
讀取數(shù)據(jù)
打開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 創(chuàng)建請求,發(fā)出請求并將結(jié)果轉(zhuǎn)化為Test數(shù)組乳讥。
- //3 取出數(shù)組中最后一個Test柱查,也就是我們在界面上只能顯示最后一個輸入信息,通過對象的屬性我們找到了之前輸入的信息云石。
- //4 將取到的信息顯示在界面上唉工,其中favoriteColor從Anyobject轉(zhuǎn)化為UIColor,Avatar從NSData轉(zhuǎn)化為UIImage留晚。
好的酵紫,這個Demo基本就完成了,我們來運行一下吧:
到了這一篇的最后部分了奖地。
數(shù)據(jù)驗證:
有時候我們對數(shù)據(jù)的內(nèi)容有所限制,比如說年齡不能是負(fù)的赋焕,在coredata中這種驗證并不用我們自己來寫代碼参歹,我們的data model就有這樣的功能。
打開我們的data model隆判,選中我們要驗證的屬性犬庇,點開右邊的屬性輔助欄僧界,如下圖所示:
在紅色框中我們可以限定最大值 和 最小值臭挽。
Note:當(dāng)我們修改我們的data model以后在運行程序會發(fā)生錯誤捂襟,原因就是我們修改了我們的model,最簡單的解決方法就是把我們的模擬器reset一下欢峰。
好的,接下來我們監(jiān)測下當(dāng)輸入超出我們的限定之后發(fā)生了什么纽帖,還記得我們的保存時的error嗎宠漩,我們將輸入的年齡為-1,我們來看一下輸出懊直。
既然發(fā)生了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
這兩句判斷語句能準(zhǔn)確的告訴我們到底是發(fā)生了什么錯誤,根據(jù)不同錯誤以及實際情況來進(jìn)行處理融撞,靈活機(jī)動晨逝。
這一篇內(nèi)容大體就是這樣了,主要講了通過對象來進(jìn)行存儲以及讀取懦铺,而這樣操作的好處就是更加方便捉貌,充分利用了swift以及xcode的特性,也不容易出錯冬念。
源代碼已上傳Github:https://github.com/superxlx/CoreDataTest2
好了趁窃,在下一篇再見。