iOSiOS数据持久化iOS&Xcode奇技淫巧

CoreData(二)

2015-04-18  本文已影响1841人  StrongX
  • 参考书籍:CORE DATA by Tutorials

亲爱的们,上一篇我们简单的讲了Core Data的存储以及读取,我们已经说过了Core Data是对象图形化管理模式,既然对象放在最前面,那么在Core Data中最正确的操作方式应该是使用对象和属性来进行操作。
这一篇的主要内容:


(1)、使用所有的Attributes的类型
在这一篇中我们也用一个Demo来演示,Demo如图所示:

已拖拽好控件
那块绿色表示最喜欢的颜色。
那只斯派克表示头像。
(一切从简,以CoreData操作为核心。)
在name和age的输入框输入数据并且选择好日期后,点击Add按钮会将name、年龄、最喜欢的颜色、生日、头像全部保存起来。
点击show按钮会跳转到下一界面,如图:
自行创建一个新的文件并于此界面联系起来,这里不演示如何操作,若有疑问请留言

在这个页面中会显示之前保存的数据。

在上一篇中我们知道在进行Core Data操作之前我们得先建立data model(数据模板),对此有问题的同学请参考[http://www.jianshu.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。
(据说勾选了这个选择框以后还容易导致数据丢失,未验证。)


(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也许会在这一栏自动填写,但经检验出错,所以还是自己重新填一下

通过对象管理类来进行存储读取有以下两个好处:

上一篇我们已经了解过,在进行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>

解释一下这一段代码:

现在运行一下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>

代码解释:

好的,这个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

好了,在下一篇再见。

上一篇下一篇

猜你喜欢

热点阅读