The Core Data Stack
直到现在我们都在依赖 Xcode's Core Data template. 但Core Data 是如何工作的呢?建立自己的 stack是必须的.
The stack 由下面四个 Core Data classes组成:
- NSManagedObjectModel
- NSPersistentStore
- NSPersistentStoreCoordinator
- NSManagedObjectContext
Create CoreDataStack:
//
// CoreDataStack.swift
// Dog Walk
//
// Created by Ricky Choi on 16/6/15.
// Copyright © 2016年 Razeware. All rights reserved.
//
import CoreData
class CoreDataStack {
let modelName = "Dog Walk"
private lazy var applicationDocumentsDirectory: NSURL = {
let urls = NSFileManager.defaultManager().URLsForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomains: NSSearchPathDomainMask.UserDomainMask) as [NSURL]
return urls[urls.count - 1]
}()
//1
lazy var context: NSManagedObjectContext = {
var managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = self.psc
return managedObjectContext
}()
//2
private lazy var psc: NSPersistentStoreCoordinator = {
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent(self.modelName)
do {
let options = [NSMigratePersistentStoresAutomaticallyOption : true]
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: options)
} catch {
print("Error adding persistent store.")
}
return coordinator
} ()
//3
private lazy var managedObjectModel: NSManagedObjectModel = {
let modelURL = NSBundle.mainBundle().URLForResource(self.modelName, withExtension: "momd")! //数据建模的名字
return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
// Save process
func saveContext() {
if context.hasChanges {
do {
try context.save()
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
abort()
}
}
}
}
//==================================================================
//AppDelegate.swift
/*
* Copyright (c) 2016 Razeware LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
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 {
// Override point for customization after application launch
let navigationController = 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()
}
}
Modeling data - 数据建模
Dog Walk.xcdatamodeld === compiled to ===> Dog Walk.momd
建立实体间的关系 Relationships
基于数据模型生成:NSManagedObject 子类 (Create NSManagedObject Subclass
//
// Dog+CoreDataProperties.swift
// Dog Walk
//
// Created by Ricky Choi on 16/6/15.
// Copyright © 2016年 Razeware. All rights reserved.
//
// Choose "Create NSManagedObject Subclass…" from the Core Data editor menu
// to delete and recreate this implementation file for your updated model.
//
import Foundation
import CoreData
extension Dog {
@NSManaged var name: String?
@NSManaged var walks: NSOrderedSet?
}
//
// Walk+CoreDataProperties.swift
// Dog Walk
//
// Created by Ricky Choi on 16/6/15.
// Copyright © 2016年 Razeware. All rights reserved.
//
// Choose "Create NSManagedObject Subclass…" from the Core Data editor menu
// to delete and recreate this implementation file for your updated model.
//
import Foundation
import CoreData
extension Walk {
@NSManaged var date: NSDate?
@NSManaged var dog: NSManagedObject?
}
// Viewcontroller.swift
/*
* Copyright (c) 2016 Razeware LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import UIKit
import CoreData
class ViewController: UIViewController, UITableViewDataSource {
var managedContext: NSManagedObjectContext!
lazy var dateFormatter: NSDateFormatter = {
let formatter = NSDateFormatter()
formatter.dateStyle = .ShortStyle
formatter.timeStyle = .MediumStyle
formatter.doesRelativeDateFormatting = true
formatter.locale = NSLocale(localeIdentifier: "zh_cn")
return formatter
}()
@IBOutlet var tableView: UITableView!
//var walks:Array<NSDate> = []
var currentDog: Dog!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.registerClass(UITableViewCell.self,
forCellReuseIdentifier: "Cell")
//增加Dog 赋值到 currentDog
let dogEntity = NSEntityDescription.entityForName("Dog", inManagedObjectContext: managedContext)
let dogName = "WormWormDog"
let dogFetch = NSFetchRequest(entityName: "Dog")
dogFetch.predicate = NSPredicate(format: "name == %@", dogName)
do {
let results = try managedContext.executeFetchRequest(dogFetch) as! [Dog]
if results.count > 0 {
//WormWormDog found, use it
currentDog = results.first
} else {
//WormWormDog not found create it
currentDog = Dog(entity: dogEntity!, insertIntoManagedObjectContext: managedContext)
currentDog.name = dogName
try managedContext.save()
}
} catch let error as NSError {
print("Error: \(error) descripton \(error.localizedDescription)")
}
}
func tableView(tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
//return walks.count
return currentDog.walks!.count
}
func tableView(tableView: UITableView,
titleForHeaderInSection section: Int) -> String? {
//return "List of Walks"
return currentDog.name!
}
func tableView(tableView: UITableView,
cellForRowAtIndexPath
indexPath: NSIndexPath) -> UITableViewCell {
let cell =
tableView.dequeueReusableCellWithIdentifier("Cell",
forIndexPath: indexPath) as UITableViewCell
//let date = walks[indexPath.row]
//cell.textLabel!.text = dateFormatter.stringFromDate(date)
//显示该Dog的Walks
let walk = currentDog.walks![indexPath.row] as! Walk
cell.textLabel!.text = dateFormatter.stringFromDate(walk.date!)
return cell
}
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
//Delete
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
//1
let walkToRemove = currentDog.walks![indexPath.row] as! Walk
//2
managedContext.deleteObject(walkToRemove)
//3
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save: \(error)")
}
//4
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
@IBAction func add(sender: AnyObject) {
//walks.append(NSDate())
//Insert a new Walk entity into Core Data
let walkEntity = NSEntityDescription.entityForName("Walk", inManagedObjectContext: managedContext)
let walk = Walk(entity: walkEntity!, insertIntoManagedObjectContext: managedContext)
walk.date = NSDate()
//Insert the new Walk into The Dog's walks set
let walks = currentDog.walks!.mutableCopy() as! NSMutableOrderedSet
walks.addObject(walk)
currentDog.walks = walks.copy() as? NSOrderedSet
//Save the managed object context
do {
try managedContext.save()
} catch let error as NSError {
print ("Could not save:\(error)")
}
tableView.reloadData()
}
}
screen: