CoreData(二)

  • 参考书籍:CORE DATA by Tutorials
  • 默认有swift基础。
  • 默认已阅读上一篇内容。

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

  • 使用所有的Attributes的类型。
  • 使用对象来进行储存以及读取数据。
  • data model的检验限制功能。

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

CoreData(二)_第1张图片
已拖拽好控件

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

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

在上一篇中我们知道在进行Core Data操作之前我们得先建立data model(数据模板),对此有问题的同学请参考[http://www.jianshu.com/p/96e2b321449c]
这是我们建立的数据模型:

CoreData(二)_第3张图片
注意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的选择框,像这样:

CoreData(二)_第4张图片

当你勾选了 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*:

CoreData(二)_第5张图片
最新的xcode也许会在这一栏自动填写,但经检验出错,所以还是自己重新填一下

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

    1. 充分利用了xcode和编译器。
  • 2.你可以重定义已经存在的方法。
    有些方法不被允许继承

上一篇我们已经了解过,在进行Core Data操作时第一步就是获取managedContext(‘暂存器’)。上一篇我们通过 application.delegate来获取‘暂存器’,但是这样操作看起来更像是一个全局变量。这一篇我用类与类之间的属性传递的方法,来获取这个‘暂存器’对象,打开AppDelegate.swift
插入以下代码:


func application(application:UIApplication,didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let viewController = self.window!.rootViewController as ViewController
viewController.managedContext = self.managedObjectContext
return true
}

打开ViewController.swift,添加头文件“import CoreData”,添加一个全局变量。

    //这个变量就是我们的‘暂存器’,而这个暂存器在AppDelegate.swift中已经初始化。
    var managedContext:NSManagedObjectContext!

给addButton方法添加代码

 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)")
}

解释一下这一段代码:

  • //1 获取在屏幕中输入的各种信息。
  • //2 新建一个Test对象TestObject,使用初始化方法
    init(entity: NSEntityDescription, insertIntoManagedObjectContext context: NSManagedObjectContext?)
  • //3 给新建的TestObject的变量赋值。
  • //4 保存‘暂存器’。
    是不是使用对象来进行保存方便许多,是的!

现在运行一下app,填写信息(age一栏请填写整数,否则出错,这里只考虑CoreData相关操作),点击add按钮以后信息被储存,点击show按钮以后跳转到下一界面,但是并没有进行任何操作,现在给showViewController添加代码。

读取数据
打开ShowViewController.swift,在viewDidLoad()中添加以下代码。


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

}

代码解释:

  • //1 获取‘暂存器’。
  • //2 创建请求,发出请求并将结果转化为Test数组。
  • //3 取出数组中最后一个Test,也就是我们在界面上只能显示最后一个输入信息,通过对象的属性我们找到了之前输入的信息。
  • //4 将取到的信息显示在界面上,其中favoriteColor从Anyobject转化为UIColor,Avatar从NSData转化为UIImage。

好的,这个Demo基本就完成了,我们来运行一下吧:

CoreData(二)_第6张图片
别忘了点击Add按钮
CoreData(二)_第7张图片
成功显示,Demo的确够简陋~~~

到了这一篇的最后部分了。
数据验证:

有时候我们对数据的内容有所限制,比如说年龄不能是负的,在coredata中这种验证并不用我们自己来写代码,我们的data model就有这样的功能。

打开我们的data model,选中我们要验证的属性,点开右边的属性辅助栏,如下图所示:

CoreData(二)_第8张图片
年龄不能小于0,记得打上边上的√

在红色框中我们可以限定最大值 和 最小值。

Note:当我们修改我们的data model以后在运行程序会发生错误,原因就是我们修改了我们的model,最简单的解决方法就是把我们的模拟器reset一下。


CoreData(二)_第9张图片
对data model的任何修改都可能使之发生错误,这个时候不妨把这个按钮按一下

好的,接下来我们监测下当输入超出我们的限定之后发生了什么,还记得我们的保存时的error吗,我们将输入的年龄为-1,我们来看一下输出。

CoreData(二)_第10张图片
error.userInfo输出了刚才输入的全部信息,包括错误信息

既然发生了error,个么问题来了,如何处理error?


var error: NSError?
if !managedContext.save(&error) {
println("Could not save (error), (error!.userInfo)")
if error!.code == NSValidationNumberTooLargeError{
println("值过大")
}
if error!.code == NSValidationNumberTooLargeError {
println("值过小")
}
}

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

这两句判断语句能准确的告诉我们到底是发生了什么错误,根据不同错误以及实际情况来进行处理,灵活机动。


这一篇内容大体就是这样了,主要讲了通过对象来进行存储以及读取,而这样操作的好处就是更加方便,充分利用了swift以及xcode的特性,也不容易出错。
源代码已上传Github:https://github.com/superxlx/CoreDataTest2

好了,在下一篇再见。

你可能感兴趣的:(CoreData(二))