Skip to content

Instantly share code, notes, and snippets.

@gitbricho
Last active July 7, 2016 23:02
Show Gist options
  • Save gitbricho/9f3b07e50144c93fefab48c403807665 to your computer and use it in GitHub Desktop.
Save gitbricho/9f3b07e50144c93fefab48c403807665 to your computer and use it in GitHub Desktop.
Core Data
...
// ## アプリ・ドキュメントDIR
// Core Data 保存ファイルを保存するために使用.
lazy var applicationDocumentsDirectory: Foundation.URL = {
// ファイルマネージャを使ってアプリ・サポート・ディレクトリを取得
let urls = FileManager.default().urlsForDirectory(
.applicationSupportDirectory, inDomains: .userDomainMask)
let appSupportURL = urls[urls.count - 1]
// 取得ディレクトリ + "/CoreDataDemo_Data" を返す
print("アプリ・ドキュメントDIR: \(appSupportURL)")
return try! appSupportURL.appendingPathComponent("CoreDataDemo_Data")
}()
...
...
// ##管理オブジェクトモデル (非オプショナル)
lazy var managedObjectModel: NSManagedObjectModel = {
// "DataModel.momd" ファイルの URLを取得
// オプショナルではないので、ロードできない場合はエラー
// コンパイル後:App.xcdatamodeld --> App.momd
let modelURL = Bundle.main().urlForResource("App", withExtension: "momd")!
// 指定 URL の管理オブジェクトモデルを返す
return NSManagedObjectModel(contentsOf: modelURL)!
}()
...
...
// ## 永続ストアコーディネータ (オプショナル).
// (必要なら、保存ディレクトリを作成)
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
let fileManager = FileManager.default()
var failError: NSError? = nil
var shouldFail = false
var failureReason = "保存データの生成またはロードエラー."
// 保存ディレクトリが存在するか確認.
do {
// コンテンツ取得
let properties = try self.applicationDocumentsDirectory.resourceValues(forKeys: [URLResourceKey.isDirectoryKey])
if !properties.isDirectory! {
// エラー:指定パスのコンテンツは存在するがフォルダではない
failureReason = "データ保存用フォルダ: \(self.applicationDocumentsDirectory.path) はフォルダではない."
shouldFail = true
}
} catch {
// コンテンツが存在しない
let nserror = error as NSError
if nserror.code == NSFileReadNoSuchFileError {
do {
// 保存ディレクトリを作成する
try fileManager.createDirectory(atPath: self.applicationDocumentsDirectory.path!,
withIntermediateDirectories: true, attributes: nil)
} catch {
failError = nserror
}
} else {
failError = nserror
}
}
// ストアコーディネータ(オプショナル)を作成
var coordinator: NSPersistentStoreCoordinator? = nil
if failError == nil {
// 保存ディレクトリの確認(または作成)に成功したらコーディネータを生成
coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
// アプリ・ドキュメントDIR + "/CoreDataDemo.storedata" の url を取得
let url = try! self.applicationDocumentsDirectory.appendingPathComponent("CoreDataDemo.storedata")
do {
// コーディネータに取得 url の永続ストアファイルを追加
try coordinator!.addPersistentStore(ofType: NSXMLStoreType, configurationName: nil, at: url, options: nil)
} catch {
// エラー処理をここに記述.
/*
ここで扱う典型的なエラー:
* 永続ストアへのアクセス不可(原因:デバイスロック時のパーミッション|データプロテクト)
* デバイスの容量不足
* ストアが現モデルバージョンにマイグレートできなかった
実際の問題が何か判定するためにメッセージを調べる。
*/
failError = error as NSError
}
}
if shouldFail || (failError != nil) {
// Report any error we got.
if let error = failError {
NSApplication.shared().presentError(error)
fatalError("Unresolved error: \(error), \(error.userInfo)")
}
fatalError("Unsresolved error: \(failureReason)")
} else {
// コーディネータを返す
return coordinator!
}
}()
...
...
// ##管理オブジェクトコンテキスト (オプショナル).
// すでに永続ストアコーディネータと結合されている.
lazy var managedObjectContext: NSManagedObjectContext = {
// 永続ストアコーディネータを取得(オプショナル)
let coordinator = self.persistentStoreCoordinator
// 管理オブジェクトコンテキストを生成
var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
// コンテキストに永続ストアコーディネータを設定
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
...
...
// アプリ終了前に呼ばれる.
// アプリの管理オブジェクト・コンテキストでの変更を保存.
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplicationTerminateReply {
if !managedObjectContext.commitEditing() {
NSLog("\(NSStringFromClass(self.dynamicType)) 終了のための編集コミットに失敗.")
return .terminateCancel
}
if !managedObjectContext.hasChanges {
return .terminateNow
}
do {
try managedObjectContext.save()
} catch {
let nserror = error as NSError
// ここにアプリ特有のリカバリ処理を記述:
...
let answer = alert.runModal()
if answer == NSAlertSecondButtonReturn {
return .terminateCancel
}
}
// If we got here, it is time to quit.
return .terminateNow
}
...
...
// アプリ終了前に呼ばれる.
// アプリの管理オブジェクト・コンテキストでの変更を保存.
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplicationTerminateReply {
//管理オブジェクトを変更
// ここでは新しい社員を作成
let entity = NSEntityDescription.entity(forEntityName: "Syain", in: managedObjectContext)
let syain: SyainMO = SyainMO(entity: entity!, insertInto: managedObjectContext)
syain.simei = "山田太郎"
syain.nyusyaBi = "2013/04/01"
syain.seinenGappi = "1982/11/23"
if !managedObjectContext.commitEditing() {
...
}
...
do {
// 変更を保存
try managedObjectContext.save()
//変更が保存されたことの確認とデータ取得機能のテスト
let fetchReq: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Syain")
let results = try! managedObjectContext.fetch(fetchReq) as! [SyainMO]
for syain in results {
print("氏名:\(syain.simei!), 生年月日:\(syain.seinenGappi!), 入社日:\(syain.nyusyaBi!)")
}
} catch {
let nserror = error as NSError
// ここにアプリ特有のリカバリ処理を記述:
...
}
// If we got here, it is time to quit.
return .terminateNow
}
...
...
// 保存アクション:
@IBAction func saveAction(_ sender: AnyObject?) {
let busyoService = BusyoService(managedObjectContext)
let syainService = SyainService(managedObjectContext)
// -- 一旦全件削除する
busyoService.delete(busyoService.fetchRequest())
syainService.delete(syainService.fetchRequest())
// -- 2件の部署を追加する
let busyo1 = busyoService.create(busyoMei: "営業部")
let busyo2 = busyoService.create(busyoMei: "製造部")
// -- 3件の社員を追加する
let syain1 = syainService.create(simei: "吉岡三郎",
nyusyaBi: "2012/04/01", seinenGappi: "1976/05/22")
syain1.busyo = busyo1 //関係設定 : 所属 = 営業部
let syain2 = syainService.create(simei: "山田花子",
nyusyaBi: "2014/06/22", seinenGappi: "1980/10/15")
syain2.busyo = busyo2 //関係設定:所属 = 製造部
let syain3 = syainService.create(simei: "山田太郎",
nyusyaBi: "2015/04/01", seinenGappi: "1993/07/12")
syain3.busyo = busyo1 //関係設定 : 所属 = 営業部
if !managedObjectContext.commitEditing() {
NSLog("\(NSStringFromClass(self.dynamicType)) 保存前の編集コミット失敗.")
}
if managedObjectContext.hasChanges {
do {
// アプリの管理オブジェクト・コンテキストに save:メッセージを送信.
try managedObjectContext.save()
} catch {
// エラー発生をユーザーに知らせる.
let nserror = error as NSError
NSApplication.shared().presentError(nserror)
}
}
// -- 氏名検索
let result1 = syainService.findBySimei("山田花子")
printResults(title: ">氏名検索:", results: result1)
// -- 氏名あいまい検索
let result1b = syainService.findLikeSimei("山田*")
printResults(title: ">氏名あいまい検索:", results: result1b)
// -- 生年月日検索
let result2 = syainService.findBySeinenGappi("1976/05/22")
printResults(title: ">生年月日検索:", results: result2)
// -- 全件取得
let result3 = syainService.findAll()
printResults(title: ">全件取得:", results: result3)
}
func printResults(title: String, results: [SyainMO]) {
print(title)
for syain in results {
print("-------------------------------")
print("simei: \(syain.simei!)")
print("seinenGappi: \(syain.seinenGappi!)")
print("nyusyaBi: \(syain.nyusyaBi!)")
print("勤続年月:\(syain.kinzokuNenGetu)")
}
}
...
import Foundation
import CoreData
/**
* Core Data 部署サービス.
*/
class BusyoService {
// MARK: プロパティ
let mc: NSManagedObjectContext
// MARK: イニシャライザ
init(_ context: NSManagedObjectContext) {
mc = context
}
// MARK: メソッド -
/// 全件取得
func findAll() -> [BusyoMO] {
let fetchReq = fetchRequest()
return try! mc.fetch(fetchReq) as! [BusyoMO]
}
/// 汎用クエリー検索
func findByPredicate(_ pred: Predicate) -> [BusyoMO] {
return try! mc.fetch(fetchRequest(pred: pred)) as! [BusyoMO]
}
/// クエリーの生成
func fetchRequest(pred :Predicate?=nil) -> NSFetchRequest<NSFetchRequestResult> {
let fetchReq: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Busyo")
if pred != nil {
fetchReq.predicate = pred
}
return fetchReq
}
/// 新規作成(管理コンテキストへ追加)
func create(busyoMei: String) -> BusyoMO {
let entity = NSEntityDescription.entity(forEntityName: "Busyo", in: mc)
let busyo: BusyoMO = BusyoMO(entity: entity!, insertInto: mc)
busyo.busyoMei = busyoMei
return busyo
}
/// 指定部署の削除
func delete(_ entity: BusyoMO) {
mc.delete(entity)
}
/// 条件にマッチする部署を削除
func delete(_ fetchReq: NSFetchRequest<NSFetchRequestResult>) {
let results = try! mc.fetch(fetchReq) as! [BusyoMO]
for del in results {
delete(del)
}
}
}
<?xml version="1.0" standalone="no"?>
<!DOCTYPE database SYSTEM "file:///System/Library/DTDs/CoreData.dtd">
<database>
<databaseInfo>
...
</databaseInfo>
<object type="SYAIN" id="z149">
<attribute name="nyusyabi" type="string">2015/04/01</attribute>
<attribute name="simei" type="string">山田太郎</attribute>
<attribute name="seinengappi" type="string">1993/07/12</attribute>
<relationship name="busyo" type="0/1" destination="BUSYO" idrefs="z152"></relationship>
</object>
<object type="SYAIN" id="z150">
<attribute name="nyusyabi" type="string">2012/04/01</attribute>
<attribute name="simei" type="string">吉岡三郎</attribute>
<attribute name="seinengappi" type="string">1976/05/22</attribute>
<relationship name="busyo" type="0/1" destination="BUSYO" idrefs="z152"></relationship>
</object>
<object type="BUSYO" id="z151">
<attribute name="busyomei" type="string">製造部</attribute>
<relationship name="syozokusyain" type="0/0" destination="SYAIN" idrefs="z153"></relationship>
</object>
<object type="BUSYO" id="z152">
<attribute name="busyomei" type="string">営業部</attribute>
<relationship name="syozokusyain" type="0/0" destination="SYAIN" idrefs="z149 z150"></relationship>
</object>
<object type="SYAIN" id="z153">
<attribute name="nyusyabi" type="string">2014/06/22</attribute>
<attribute name="simei" type="string">山田花子</attribute>
<attribute name="seinengappi" type="string">1980/10/15</attribute>
<relationship name="busyo" type="0/1" destination="BUSYO" idrefs="z151"></relationship>
</object>
</database>
import Cocoa
/**
* Core Data 社員サービス.
*/
class SyainService {
// MARK: プロパティ
let mc: NSManagedObjectContext
// MARK: イニシャライザ
init(_ context: NSManagedObjectContext) {
mc = context
}
// MARK: メソッド -
/// 全件取得
func findAll() -> [SyainMO] {
let fetchReq = fetchRequest()
return try! mc.fetch(fetchReq) as! [SyainMO]
}
/// 氏名検索
func findBySimei(_ simei:String) -> [SyainMO] {
return try! mc.fetch(
fetchRequest(pred: Predicate(format: "simei == %@", simei))) as! [SyainMO]
}
/// 氏名あいまい検索
func findLikeSimei(_ simeiLike: String) -> [SyainMO] {
return try! mc.fetch(
fetchRequest(pred: Predicate(format: "simei LIKE %@", simeiLike))) as! [SyainMO]
}
/// 生年月日検索
func findBySeinenGappi(_ seinenGappi: String) -> [SyainMO] {
return try! mc.fetch(
fetchRequest(pred: Predicate(format: "seinenGappi == %@", seinenGappi))) as! [SyainMO]
}
/// 汎用クエリー検索
func findByPredicate(_ pred: Predicate) -> [SyainMO] {
return try! mc.fetch(fetchRequest(pred: pred)) as! [SyainMO]
}
/// クエリーの生成
func fetchRequest(pred :Predicate?=nil) -> NSFetchRequest<NSFetchRequestResult> {
let fetchReq: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Syain")
if pred != nil {
fetchReq.predicate = pred
}
return fetchReq
}
/// 新規作成(管理コンテキストへ追加)
func create(simei: String, nyusyaBi: String, seinenGappi: String = "") -> SyainMO {
let entity = NSEntityDescription.entity(forEntityName: "Syain", in: mc)
let syain: SyainMO = SyainMO(entity: entity!, insertInto: mc)
syain.simei = simei
syain.nyusyaBi = nyusyaBi
syain.seinenGappi = seinenGappi
return syain
}
/// 更新処理
// 1)条件にマッチする社員を取得して:
// let updSyain = findByXXX(条件)
// 2)データを修正:
// updSyain.simei = "氏名の変更"
// 3)データを保存:
// save()
/// 保存処理: 追加|更新
func save() {
do {
try mc.save()
} catch let error as NSError {
print("保存失敗: \(error), \(error.userInfo)")
}
}
/// 指定社員の削除
func delete(_ entity: SyainMO) {
mc.delete(entity)
}
/// 条件にマッチする社員を削除
func delete(_ fetchReq: NSFetchRequest<NSFetchRequestResult>) {
let results = try! mc.fetch(fetchReq) as! [SyainMO]
for del in results {
delete(del)
}
}
}
// SyainMO 拡張
extension SyainMO {
// 勤続年月: 計算プロパティのテスト用
// 日数までは計算していない.
var kinzokuTuki: Int {
let dateFormater = DateFormatter()
dateFormater.dateFormat = "yyyy/MM/dd"
let nyusyaDate = dateFormater.date(from: self.nyusyaBi!)
let calendar: Calendar! = Calendar(calendarIdentifier: Calendar.Identifier.gregorian)
let keikaTuki = calendar.components(.month,
from: nyusyaDate!, to: Date(), options: [])
return keikaTuki.month!
}
var kinzokuNen: Int {
return kinzokuTuki / 12
}
var kinzokuNenGetu: String {
return "\(kinzokuNen)年\(kinzokuTuki % 12)ヶ月"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment