Step by Step Do IOS Swift CoreData Simple Demo

简单介绍

这篇文章记录了在 IOS 中使用 Swift 操作 CoreData 的一些基础性内容,因为缺乏文档,基本上都是自行实验的结果。错漏不可避免,还请谅解。

部分内容借鉴了 Tim Roadley 的《Learning.Core.Data.for.iOS(2013.11)》, 这本书主要介绍 ObjC的 CoreData 。


创建一个新 XCode
项目

  • 创建一个新的 XCode 项目。

  • 创建一个 Empty Application

  • 填写项目相关信息,如设置项目名称为: SwiftCoreDataSimpleDemo。 注意选择语言为 Swift。 而且勾选上 Use Core Data。

  • 选择存储项目的文件夹

  • 创建的新项目例如以下图所看到的


改动 Core Data Model

  • 选择 SwiftCoreDataSimpleDemo.xcdatamodeld 文件,眼下还是空的。

  • 创建两个 Entity。 分别命名为 Family 和 Member。

  • 在生成模型文件之前,我们能够创建一个名为 models 的 Group , 用于存放生成的模型文件。

  • 选中 SwiftCoreDataSimpleDemo.xcdatamodeld 文件的某个 Entity 之后,可以在 Editor 菜单中找到 Create NSManagedObject Subclass,选择此项目,開始创建模型文件。

  • 尾随向导。完毕模型创建,能够选中全部的 Entity ,并将存储位置指定为我们刚创建的 models Group 中。

  • 在结束之前。XCode 会弹出对话框,问是否创建用于 Swift 和 ObjC 协同工作的库文件 SwiftCoreDataSimpleDemo-Bridging-Header.h, 此时当然是选择 Yes。

生成完毕之后,就行在 Project 中看见新的模型文件了。

此时,SwiftCoreDataSimpleDemo-Bridging-Header.h 还是空的,我们须要在当中添加须要被 Swift 訪问的头文件。结果例如以下图所看到的:

#import "Family.h"
#import "Member.h"


改动 AppDelegate

和新建 ObjC App 类似。新建项目将操作 CoreData 的代码加入在 AppDelegate.swift 文件里。为了可以使代码更简洁和清晰。我们将这部分代码提炼出来。移动到 CoreDataHelper.swift 中去。

  • 打开原始的 AppDelegate.swift。在程序的后半部分,可以看见操作 CoreData 相关的代码.例如以下图所看到的。

  • 创建新 CoreDataHelper.swift 文件。

    改动文件名称为 CoreDataHelper。

  • 在 AppDelegate.swift 中将 func saveContext () 及其后面的代码选中。转移到 CoreDataHelper.swift 文件里。并对其做些小调整,将所用到的项目名称提成常量,放在 CoreDataHelper 前部,这样,以后假设须要在历史项目中使用 CoreDataHelper,就十分方便了。

完毕后的 CoreDataHelper.swift 代码例如以下:

//
//  CoreDataHelper.swift
//  SwiftCoreDataSimpleDemo
//
//  Created by CHENHAO on 14-6-7.
//  Copyright (c) 2014年 CHENHAO. All rights reserved.
//

import CoreData

class CoreDataHelper{

    let storeName = "SwiftCoreDataSimpleDemo"
    let storeFilename = "SwiftCoreDataSimpleDemo.sqlite"

    // #pragma mark - Core Data stack

    // Returns the managed object context for the application.
    // If the context doesn‘t already exist, it is created and bound to the persistent store coordinator for the application.
    var managedObjectContext: NSManagedObjectContext {
    if !_managedObjectContext {
        let coordinator = self.persistentStoreCoordinator
        if coordinator != nil {
            _managedObjectContext = NSManagedObjectContext()
            _managedObjectContext!.persistentStoreCoordinator = coordinator
        }
        }
        return _managedObjectContext!
    }
    var _managedObjectContext: NSManagedObjectContext? = nil

    // Returns the managed object model for the application.
    // If the model doesn‘t already exist, it is created from the application‘s model.
    var managedObjectModel: NSManagedObjectModel {
    if !_managedObjectModel {
        let modelURL = NSBundle.mainBundle().URLForResource(storeName, withExtension: "momd")
        _managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)
        }
        return _managedObjectModel!
    }
    var _managedObjectModel: NSManagedObjectModel?

= nil

    // Returns the persistent store coordinator for the application.
    // If the coordinator doesn‘t already exist, it is created and the application‘s store added to it.
    var persistentStoreCoordinator: NSPersistentStoreCoordinator {
    if !_persistentStoreCoordinator {
        let storeURL = self.applicationDocumentsDirectory.URLByAppendingPathComponent(storeFilename)
        var error: NSError? = nil
        _persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
        if _persistentStoreCoordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil, error: &error) == nil {
            /*
            Replace this implementation with code to handle the error appropriately.

            abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

            Typical reasons for an error here include:
            * The persistent store is not accessible;
            * The schema for the persistent store is incompatible with current managed object model.
            Check the error message to determine what the actual problem was.

            If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application‘s resources directory instead of a writeable directory.

            If you encounter schema incompatibility errors during development, you can reduce their frequency by:
            * Simply deleting the existing store:
            NSFileManager.defaultManager().removeItemAtURL(storeURL, error: nil)

            * Performing automatic lightweight migration by passing the following dictionary as the options parameter:
            [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true}

            Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.

            */
            //println("Unresolved error \(error), \(error.userInfo)")
            abort()
        }
        }
        return _persistentStoreCoordinator!
    }
    var _persistentStoreCoordinator: NSPersistentStoreCoordinator? = nil

    // #pragma mark - Application‘s Documents directory

    // Returns the URL to the application‘s Documents directory.
    var applicationDocumentsDirectory: NSURL {
    let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
        return urls[urls.endIndex-1] as NSURL
    }

    func saveContext () {
        var error: NSError? = nil
        let managedObjectContext = self.managedObjectContext
        if managedObjectContext != nil {
            if managedObjectContext.hasChanges && !managedObjectContext.save(&error) {
                // Replace this implementation with code to handle the error appropriately.
                // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                //println("Unresolved error \(error), \(error.userInfo)")
                abort()
            }
        }
    }
}
  • 改动 AppDelegate.swift。

    并创建一个 CoreDataHelper 的实例。用于操作 CoreData。

applicationWillTerminate(application: UIApplication) 方法之后的内容所有替换为下面代码。

var cdh: CoreDataHelper {
if !_cdh {
    _cdh = CoreDataHelper()
    }
    return _cdh!
}
var _cdh: CoreDataHelper?

= nil
  • 改动 AppDelegate.swift。以自己主动保存 CoreData。

代码例如以下:

func applicationDidEnterBackground(application: UIApplication) {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.

    self.cdh.saveContext()
}
...
func applicationWillTerminate(application: UIApplication) {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    // Saves changes in the application‘s managed object context before the application terminates.

    self.cdh.saveContext()
}

操作模型对象

接下来我们将在 AppDelegate.swift 中创建一个訪问 CoreData 的 demoFamily 方法,用于操作 CoreData。这段代码放在
func applicationDidBecomeActive(application: UIApplication) 中运行,操作结果从 Log 文件里查看。

func applicationDidBecomeActive(application: UIApplication) {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.

    self.demoFamily()
}

demoFamily() 的详细实现例如以下,代码说明请參考凝视:

func demoFamily(){
    var newItemNames = ["Apples", "Milk", "Bread", "Cheese", "Sausages", "Butter", "Orange Juice", "Cereal", "Coffee", "Eggs", "Tomatoes", "Fish"]

    // add families
    NSLog(" ======== Insert ======== ")

    for newItemName in newItemNames {
        var newItem: Family = NSEntityDescription.insertNewObjectForEntityForName("Family", inManagedObjectContext: self.cdh.managedObjectContext) as Family

        newItem.name = newItemName
        NSLog("Inserted New Family for \(newItemName) ")
    }

    //self.cdh.saveContext()

    //fetch families
    NSLog(" ======== Fetch ======== ")

    var error: NSError? = nil
    var fReq: NSFetchRequest = NSFetchRequest(entityName: "Family")

    // 设置过滤条件
    fReq.predicate = NSPredicate(format:"name CONTAINS ‘B‘ ")

    // 设置结果排序规则。此处设置为按 Name 逆序
    var sorter: NSSortDescriptor = NSSortDescriptor(key: "name" , ascending: false)
    fReq.sortDescriptors = [sorter]

    var result = self.cdh.managedObjectContext.executeFetchRequest(fReq, error:&error)
    for resultItem : AnyObject in result {
        var familyItem = resultItem as Family
        NSLog("Fetched Family for \(familyItem.name) ")
    }

    //delete families
    NSLog(" ======== Delete ======== ")

    fReq = NSFetchRequest(entityName: "Family")
    result = self.cdh.managedObjectContext.executeFetchRequest(fReq, error:&error)

    for resultItem : AnyObject in result {
        var familyItem = resultItem as Family
        NSLog("Deleted Family for \(familyItem.name) ")
        self.cdh.managedObjectContext.deleteObject(familyItem)
    }

    //self.cdh.saveContext()

    NSLog(" ======== Check Delete ======== ")

    result = self.cdh.managedObjectContext.executeFetchRequest(fReq, error:&error)
    if result.isEmpty {
        NSLog("Deleted All Families")
    }
    else{
        for resultItem : AnyObject in result {
            var familyItem = resultItem as Family
            NSLog("Fetched Error Family for \(familyItem.name) ")
        }
    }
}

Log输出例如以下:

2014-06-07 14:01:53.717 SwiftCoreDataSimpleDemo[18348:1419062] Application windows are expected to have a root view controller at the end of application launch
2014-06-07 14:01:54.100 SwiftCoreDataSimpleDemo[18348:1419062]  ======== Insert ========
2014-06-07 14:01:54.115 SwiftCoreDataSimpleDemo[18348:1419062] Inserted New Family for Apples
2014-06-07 14:01:54.115 SwiftCoreDataSimpleDemo[18348:1419062] Inserted New Family for Milk
2014-06-07 14:01:54.115 SwiftCoreDataSimpleDemo[18348:1419062] Inserted New Family for Bread
2014-06-07 14:01:54.116 SwiftCoreDataSimpleDemo[18348:1419062] Inserted New Family for Cheese
2014-06-07 14:01:54.116 SwiftCoreDataSimpleDemo[18348:1419062] Inserted New Family for Sausages
2014-06-07 14:01:54.116 SwiftCoreDataSimpleDemo[18348:1419062] Inserted New Family for Butter
2014-06-07 14:01:54.117 SwiftCoreDataSimpleDemo[18348:1419062] Inserted New Family for Orange Juice
2014-06-07 14:01:54.117 SwiftCoreDataSimpleDemo[18348:1419062] Inserted New Family for Cereal
2014-06-07 14:01:54.117 SwiftCoreDataSimpleDemo[18348:1419062] Inserted New Family for Coffee
2014-06-07 14:01:54.118 SwiftCoreDataSimpleDemo[18348:1419062] Inserted New Family for Eggs
2014-06-07 14:01:54.118 SwiftCoreDataSimpleDemo[18348:1419062] Inserted New Family for Tomatoes
2014-06-07 14:01:54.118 SwiftCoreDataSimpleDemo[18348:1419062] Inserted New Family for Fish
2014-06-07 14:01:54.118 SwiftCoreDataSimpleDemo[18348:1419062]  ======== Fetch ========
2014-06-07 14:01:54.121 SwiftCoreDataSimpleDemo[18348:1419062] Fetched Family for Butter
2014-06-07 14:01:54.122 SwiftCoreDataSimpleDemo[18348:1419062] Fetched Family for Bread
2014-06-07 14:01:54.122 SwiftCoreDataSimpleDemo[18348:1419062]  ======== Delete ========
2014-06-07 14:01:54.123 SwiftCoreDataSimpleDemo[18348:1419062] Deleted Family for Tomatoes
2014-06-07 14:01:54.123 SwiftCoreDataSimpleDemo[18348:1419062] Deleted Family for Cereal
2014-06-07 14:01:54.123 SwiftCoreDataSimpleDemo[18348:1419062] Deleted Family for Orange Juice
2014-06-07 14:01:54.123 SwiftCoreDataSimpleDemo[18348:1419062] Deleted Family for Eggs
2014-06-07 14:01:54.124 SwiftCoreDataSimpleDemo[18348:1419062] Deleted Family for Milk
2014-06-07 14:01:54.124 SwiftCoreDataSimpleDemo[18348:1419062] Deleted Family for Butter
2014-06-07 14:01:54.124 SwiftCoreDataSimpleDemo[18348:1419062] Deleted Family for Sausages
2014-06-07 14:01:54.125 SwiftCoreDataSimpleDemo[18348:1419062] Deleted Family for Cheese
2014-06-07 14:01:54.125 SwiftCoreDataSimpleDemo[18348:1419062] Deleted Family for Apples
2014-06-07 14:01:54.125 SwiftCoreDataSimpleDemo[18348:1419062] Deleted Family for Bread
2014-06-07 14:01:54.125 SwiftCoreDataSimpleDemo[18348:1419062] Deleted Family for Fish
2014-06-07 14:01:54.126 SwiftCoreDataSimpleDemo[18348:1419062] Deleted Family for Coffee
2014-06-07 14:01:54.126 SwiftCoreDataSimpleDemo[18348:1419062]  ======== Check Delete ========
2014-06-07 14:01:54.127 SwiftCoreDataSimpleDemo[18348:1419062] Deleted All Families
Program ended with exit code: 9

不工作的 Member.swift
代码

參考 Swift 文档,尝试创建 Member.swift,编译通过,执行測试失败。因文档有限,没法进一步确定原因。记录在此,以供大家探讨。

Swift 文档的相关说明例如以下,Implementing Core Data
Managed Object Subclasses

Implementing Core Data Managed Object Subclasses

Core Data provides the underlying storage and implementation of properties in subclasses
 of the NSManagedObject class. Add the @NSManaged attribute before each property definition
  in your managed object subclass that corresponds to an attribute or relationship in your
  Core Data model. Like the @dynamic attribute in Objective-C, the @NSManaged attribute
  informs the Swift compiler that the storage and implementation of a property will be
  provided at runtime. However, unlike @dynamic, the @NSManaged attribute is available only
  for Core Data support.

依据文档编写 Member.swift 例如以下:

import CoreData

class Member: NSManagedObject {
    @NSManaged var name: String
    @NSManaged var sex: String
    @NSManaged var birthday: NSDate
}

将 SwiftCoreDataSimpleDemo-Bridging-Header.h 中的 Member.h 行凝视掉:

#import "Family.h"
// #import "Member.h"

执行之后,编译成功,但执行出错闪退,出错界面例如以下。


代码地址

https://github.com/iascchen/SwiftCoreDataSimpleDemo/



打完收工



Author : iascchen(at)gmail(dot)com

Date : 2014-6-7

新浪微博 : @问天鼓

时间: 2024-11-01 03:28:37

Step by Step Do IOS Swift CoreData Simple Demo的相关文章

Swift CoreData 的奇怪问题

今天尝试了一下Swift CoreData 遇到一个很奇怪的问题: 当运行项目的时候, 会提示, 找不到与实体对应的class 文件,但在实体中,文件确实是创建过的,也实际存在 运行到这个地方, xcode不会死掉,当点击"step over"的时候, 会继续执行 当我要输出 取到的结果时, 又会提示:NSArray element failed to match the swift array element type 怎么调试都无法通过, 后来经过查找资料才知道,需要在与实体对应的

C# 2012 step by step 学习笔记8 CHAPTER 9 Creating Value types with enumerations and Structures

C# 2012 step by step 学习笔记8 CHAPTER 9 Creating Value types with enumerations and Structures things about 1. Declare an enumeration type. 2. Create and use an enumeration type. 3. Declare a structure type. 4. Create and use a structure type. 5. Explain

数论之高次同余方程(Baby Step Giant Step + 拓展BSGS)

什么叫高次同余方程?说白了就是解决这样一个问题: A^x=B(mod C),求最小的x值. baby step giant step算法 题目条件:C是素数(事实上,A与C互质就可以.为什么?在BSGS算法中是要求a^m在%c条件下的逆元的,如果a.c不互质根本就没有逆元.) 如果x有解,那么0<=x<C,为什么? 我们可以回忆一下欧拉定理: 对于c是素数的情况,φ(c)=c-1 那么既然我们知道a^0=1,a^φ(c)=1(在%c的条件下).那么0~φ(c)必定是一个循环节(不一定是最小的)

Git Step by Step – (8) Git的merge和rebase

前面一篇文章中提到了"git pull"等价于"git fetch"加上"git merge",然后还提到了pull命令支持rebase模式,这篇文章就介绍一下merge和rebase之间有什么差别. 由于我们主要是想看看merge跟rebase之间的区别,这里就是用本地仓库的分支进行演示了. merge 其实在介绍分支的那篇文章中已经介绍过了一些分支merge的内容,这里就进行一些补充和总结. 下面我们基于本地一个仓库开始介绍,当前仓库的分支情

[IOS]swift自定义uicollectionviewcell

刚刚接触swift以及ios,不是很理解有的逻辑,导致某些问题.这里分享一下swift自定义uicollectionviewcell 首先我的viewcontroller不是直接继承uicollectionviewcontroller,而是添加的uicollectionview到我的storyboard, 然后再新建一个swift的文件,让这个swift继承uicollectionviewcell import Foundation class SVGCell :UICollectionView

iOS:Swift界面实例1, 简单界面

Apple推出了基于Objective-C的新语言Swift. 通过实例, 我们可以很好的感受这门新语言 注意事项: 在XCode6_Beta中, 如果有中文, IDE的自动补全功能就会失效, 所以开始调试的时候可以先用英文, 后面再用中文替代. 1. 新建iOS -> Single View Application. 2. 修改AppDelegate.swift文件 1 // 2 // AppDelegate.swift 3 // UIByCode_Swift_1_HelloWorld 4 /

Linux Booting Process: A step by step tutorial for understanding Linux boot sequence

One of the most remarkable achievement in the history of mankind is computers. Another amazing fact about this remarkable achievement called computers is that its a collection of different electronic components, and they work together in coordination

C++开发WPF,Step by Step

示例代码 使用C++来开发WPF,主要是如何在MFC(Win32)的窗口中Host WPF的Page.下面我就做个详细的介绍. 一.创建工程, 由于MFC的Wizard会生成很多用不到的代码,所以我准备从一个空的工程开始创建一个MFC的工程. a)         打开VS2005,菜单File->New->Projects-, 左面选择Visual C++->Win32,右面选择Win32 Console Application,给工程起个名字CPlusPlus_WPF, Ok进入下一

数据库设计 Step by Step (1)——扬帆启航

引言:一直在从事数据库开发和设计工作,也看了一些书籍,算是略有心得.很久之前就想针 对关系数据库设计进行整理.总结,但因为种种原因迟迟没有动手,主要还是惰性使然.今天也算是痛下决心开始这项卓绝又令我兴奋的工作.这将是一个系列的文 章,我将以讲座式的口吻展开讨论(个人偷懒,这里的总结直接拿去公司培训新人用). 系列的第一讲我们先来回答下面几个问题 数据库是大楼的根基 大多数程序员都很急切,在了解基本需求之后希望很快的进入到编码阶段(可能只有产出代码才能反映工作量),对于数据库设计思考得比较少. 这