接下来,我们创建自己的stack object。
创建一个名为CoreDataStack的swift加入到工程中。
转载请注明出处:http://blog.csdn.net/yamingwu/article/details/42297675
源代码地址:https://github.com/dnawym/StudySwift/tree/master/CoreData/Dog%20Walk
定义成员变量:
import CoreData
class CoreDataStack {
let context: NSManagedObjectContext
let psc: NSPersistentStoreCoordinator
let model: NSManagedObjectModel
let store: NSPersistentStore?
}
添加辅助函数用于保存数据和获取core data文件所在文件夹路径:
func saveContext() {
var error: NSError? = nil
if context.hasChanges && !context.save(&error) {
println("Could not save: \(error), \(error?.userInfo)")s
}
}
// 获取应用程序documents diretory的url
func applicationDocumentsDirectory() -> NSURL {
let fileManager = NSFileManager.defaultManager()
let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask) as [NSURL]
return urls[0]
}
添加init函数,构造stack
init() {
// 从硬盘加载managed object model,这里通过读取momd目录下的编译后的.xcdatamodeld文件实现
let bundle = NSBundle.mainBundle()
let modelURL = bundle.URLForResource("Dog Walk", withExtension: "momd")
model = NSManagedObjectModel(contentsOfURL: modelURL!)!
// 一旦初始化了NSManagedObjectModel,下一步是创建PSC,PSC用于桥接model和PersistentStore
psc = NSPersistentStoreCoordinator(managedObjectModel: model)
// Context的初始化没有任何参数,我们将psc连接到context上
context = NSManagedObjectContext()
context.persistentStoreCoordinator = psc
// 我们不需要手工创建PS,PSC会帮我们创建它。我们只需要为PSC提供所需的PS类型,一些配置,存放路径即可
let documentsURL = applicationDocumentsDirectory()
let storeURL = documentsURL.URLByAppendingPathComponent("Dog Walk")
let options = [NSMigratePersistentStoresAutomaticallyOption: true]
var error: NSError? = nil
store = psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: options, error: &error)
if store == nil {
println("Error adding persistent store: \(error)")
abort()
}
}
修改AppDelegate文件,构造CoreData'Stack并传递给ViewController,同时添加2个函数在应用程序进入后台和即将结束时,保存数据到文件系统中
import UIKit
import CoreData
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
lazy var coreDataStack = CoreDataStack()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let navigationController = self.window!.rootViewController as UINavigationController
let viewController = navigationController.topViewController as ViewController
viewController.managedContext = coreDataStack.context
return true
}
func applicationDidEnterBackground(application: UIApplication) {
coreDataStack.saveContext()
}
func applicationWillTerminate(application: UIApplication) {
coreDataStack.saveContext()
}
}
在ViewController中添加ManagedObjectContext成员变量
var managedContext: NSManagedObjectContext!
数据建模:
创建名为Dog Walk的CoreData model文件,在其中添加2个entity
这里,回到Dog Entity界面,创建一个指向walk的relationship
默认情况下,这种关系都是一对一的,这里需要修改为一对多,并且勾选Ordered,这样,数据自动按日期进行排序。
接下来,选择walk entity,创建一个inverse relationship指回dog,这里不用修改成to many,因为一次walk只会关联到一条狗
inverse的作用是让model知道如何找到反向路径。比如,对于一个walk记录,通过relationship可以找到对应的dog,通过inverse,model知道通过walks关系可以回到walk记录。通过选择右下角的按钮来切换视图模式到图像编辑模式。to-one是单箭头,to-many是双箭头。
创建ManagedObjectModel的子类,选择Dog Walk model并选择Dog和Walk这两个entity,最后记得选择swift编程语言,这样会生成Dog.swift和Walk.swift
然后,修改Dog和Walk数据模型的属性,将Dog改为Dog_Walk.Dog,将Walk改为Dog_Walk.Walk。这一步的目的是连接managed object子类的全名到data model中的entity。
实现对数据的持久存储:
前面我们已经完成了Core Data栈的创建,data model子类的创建,接下来我们修改ViewController来使用Core Data。
var currentDog: Dog!
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
let dogEntity = NSEntityDescription.entityForName("Dog", inManagedObjectContext: managedContext)
let dog = Dog(entity: dogEntity!, insertIntoManagedObjectContext: managedContext)
let dogName = "Fido"
let dogFetch = NSFetchRequest(entityName: "Dog")
dogFetch.predicate = NSPredicate(format: "name == %@", dogName)
var error: NSError? = nil
let result = managedContext.executeFetchRequest(dogFetch, error: &error) as [Dog]?
if let dogs = result {
if dogs.count == 0 {
currentDog = Dog(entity: dogEntity!, insertIntoManagedObjectContext: managedContext)
currentDog.name = dogName
if !managedContext.save(&error) {
println("Could not save: \(error)")
}
} else {
currentDog = dogs[0]
}
} else {
println("Could not fetch: \(error)")
}
}
接下来,修改add函数,首先创建一个walk entity并设置它的date属性,然后将这个walk实例加入到dog的walks集合中。因为dog的walks集合是immutable的,我们需要先创建一个mutable的拷贝,再将walk插入到copy中,最后将拷贝赋值回dog覆盖以前的set。
@IBAction func add(sender: AnyObject) {
// 插入新的Walk entity到Core Data中
let walkEntity = NSEntityDescription.entityForName("Walk", inManagedObjectContext: managedContext)
let walk = Walk(entity: walkEntity!, insertIntoManagedObjectContext: managedContext)
walk.date = NSDate()
// 插入新的walk到dog的walks集合中
var walks = currentDog.walks.mutableCopy() as NSMutableOrderedSet
walks.addObject(walk)
currentDog.walks = walks.copy() as NSOrderedSet
// 保存managed object context
var error: NSError?
if !managedContext.save(&error) {
println("Could not save: \(error)")
}
tableView.reloadData()
}
从Core Data中删除数据:
添加下述函数到ViewController:
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
// 获取要删除的walk对象
let walkToRemove = currentDog.walks[indexPath.row] as Walk
// 类似于添加walk到walks,现获取一个mutable拷贝,然后在拷贝中移除对应的walk,最后将拷贝赋值回dog
let walks = currentDog.walks.mutableCopy() as NSMutableOrderedSet
walks.removeObjectAtIndex(indexPath.row)
currentDog.walks = walks.copy() as NSOrderedSet
// 删除walk对象
managedContext.deleteObject(walkToRemove)
// 保存
var error: NSError?
if !managedContext.save(&error) {
println("Could not save: \(error)")
}
// 从table view中删除当前行
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
程序执行效果:
至此,我们就完成了3个实例,遛狗程序。这一节中,我们学习了如何构建自己的Core Data栈,数据模型和managed object子类,以及如何建立实例之间的关系,如何操作关系以及如何从Core Data中删除数据。
接下来,我们会更深入的学习fetch和其它更高级的iOS8 topics,这一节我们学习了基本的操作,但是还有更多需要学习的地方,are you ready?