CoreData(二)

作者: StrongX | 来源:发表于2015-04-18 21:39 被阅读1841次
    • 参考书籍: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.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。
    (据说勾选了这个选择框以后还容易导致数据丢失,未验证。)

    • 存储非标准类型数据
      有一些数据类型在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

    好了,在下一篇再见。

    相关文章

      网友评论

      • 091b0601834e:翻译别人的东西链接也不留?,而且你获得授权了么?
      • cd587cfbdff9:有时间能不能搞个oc版的,像我这种没有swift基础的有些吃力呀,牛逼

      本文标题:CoreData(二)

      本文链接:https://www.haomeiwen.com/subject/jccefttx.html