Swift のプロジェクトで CoreData でも1対多(リレーションシップ:relationship)の関係を持つデータを用意したいと思うことがあります。
CoreDataを操作するためだけのプロジェクトを用意
今回は(も?)、CoreData の操作だけのプロジェクトを用意しました(本当は、Playground で使えたら面白いんだけれど…)。
リレーションシップ(Relationship)の話に 登場するクラス
クラスの関係 としてBlog は、複数の Article を持つ状態になります
- Blog
- Article
リレーションシップ(1対多)を設定する
Blog側のリレーションシップ設定
Article側のリレーションシップ設定
クラスの設定
各クラスのファイルを書き出す
- 「Editor」 → 「Create NSManagedObject Subclass」
- Swift で書き出す
Swift 1.2 から?
どうもリレーションを設定してClassを書き出した場合、Objective-Cだと色んなfunction も書き出してくれているらしいですが、Swift 1.2 の環境では再現できませんでした(何か足りない可能性もあります…)
今回は、Blogが複数のArticleを持つ関係なので、Blogについて function を追加して対応しました。
Blog.swif
- 追加したのは addArticles() です
- Blog.articles は、もともとはNSSetでしたが変更しました
- NSSet については、Swift 1.2 で変更された箇所らしいです
- NSSet なんですが、Array とどう違うの?と納得できていない箇所だったり
Blog.swif
import Foundation
import CoreData
class Blog: NSManagedObject {
@NSManaged var title: String
@NSManaged var uuid: Int16
@NSManaged var articles: NSMutableSet
func name() -> String{
return self.title
}
func addArticles(value:Article) {
var items = self.mutableSetValueForKey("articles")
items.addObject(value)
}
}
Article.swif
- 親となるBlogについて、関連が書かれています
- Blog はnil になることもあるので、nil の許可をしています
- 余談)こうしてみると、Active Record っぽい
Article.swif
import Foundation
import CoreData
class Article: NSManagedObject {
@NSManaged var title: String
@NSManaged var body: String
@NSManaged var blog: Blog!
}
実行・制作環境
- Xcode 6.3.1
- Swift 1.2
- iOS 8.2
全体のソース
データーの登録
- 「Swift で CoreData の必要な初期データー(マスターデータ)を用意する」でデーターを登録しています
ViewController.swift
import UIKit
import CoreData
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.initMasterArticleData()
self.initMasterBlogData()
println("<--------------->")
println("")
//self.readArticleData()
self.readBlogData()
println("<--------------->")
println("")
self.updateBlog(items: self.readBlogByUuid(1))
//var results = self.readArticleByTitle()
//self.updateArticle(items: results)
//self.readArticleByTitle()
println("<--------------->")
println("")
//self.readArticleData()
self.readBlogData()
println("<--------------->")
println("")
}
func updateBlog(items:NSArray = [Blog]()) {
if items.count > 0 {
println("Yes Blog Data")
let app: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let blogContext:NSManagedObjectContext = app.managedObjectContext!
var error: NSError?
var articles = self.readArticleByTitle()
println("updateBlog -----------")
for item in items {
var blog = item as! Blog
for item_a in articles {
var article = item_a as! Article
//blog.addArticles(article)
//article.blog = blog
blog.title = "ブログの題名を変更してみた"
app.saveContext()
}
}
println("----------- updateBlog")
}else {
println("No Blog Data")
}
}
// データー読み込み:Blog
func readBlogData() -> NSArray{
let app: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let blogContext:NSManagedObjectContext = app.managedObjectContext!
let blogRequest: NSFetchRequest = NSFetchRequest(entityName: "Blog")
var results: NSArray! = blogContext.executeFetchRequest(blogRequest, error: nil)
for item in results {
var blog = item as! Blog
println("read Blog ------------")
println(blog.name())
println(blog.articles.count)
for item_a in blog.articles {
println("blog.articles ----------")
var article = item_a as! Article
println(article.title)
println("---------- blog.articles")
}
println("------------ read Blog")
}
return results
}
// データー読み込み:Article
func readArticleData() -> NSArray{
let app: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let articleContext:NSManagedObjectContext = app.managedObjectContext!
let articleRequest: NSFetchRequest = NSFetchRequest(entityName: "Article")
var results: NSArray! = articleContext.executeFetchRequest(articleRequest, error: nil)
for item in results {
var article = item as! Article
println("read.article ------------")
println(article.title)
if article.blog != nil {
println("article.blog ----------")
println(article.blog.title)
println("---------- article.blog")
}
println("------------ read.article")
}
return results
}
// データー読み込み:
func readBlogByUuid(uuid:NSNumber) ->NSArray {
let app: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let blogContext:NSManagedObjectContext = app.managedObjectContext!
let blogRequest: NSFetchRequest = NSFetchRequest(entityName: "Blog")
let predicate = NSPredicate(format: "%K == %@", "uuid", uuid)
blogRequest.predicate = predicate
var error: NSError?
var results: NSArray = []
results = blogContext.executeFetchRequest(blogRequest, error: nil)!
for item in results {
var blog = item as! Blog
println("readBlogByUuid ------------")
println(blog.title)
println("------------ readBlogByUuid")
}
return results
}
// データー読み込み:Articleを題名指定で
func readArticleByTitle(title:String? = "題名です") ->NSArray{
println("readArticleByTitle ------------")
println(title)
let app: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let articleContext:NSManagedObjectContext = app.managedObjectContext!
let articleRequest: NSFetchRequest = NSFetchRequest(entityName: "Article")
// http://qiita.com/yusuga/items/8fd531ebd8f5e72bb97b
// LIKE句 じゃなくて CONTAINS を使うと良いみたい
let predicate = NSPredicate(format: "%K CONTAINS[cd] %@", "title", title!)
articleRequest.predicate = predicate
var error: NSError?
var results: NSArray = []
results = articleContext.executeFetchRequest(articleRequest, error: nil)!
for item in results {
var article = item as! Article
println("readArticleByTitle ------------")
println(article.title)
println("------------ readArticleByTitle")
}
println("------------ readArticleByTitle")
return results
}
// データー更新:Article
func updateArticle(items:NSArray = [Article]()){
if items.count > 0 {
println("Yes Data ------------")
let app: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let articleContext:NSManagedObjectContext = app.managedObjectContext!
var error: NSError?
for item in items {
var article = item as! Article
println(article.title)
article.title = "「題名です」を書き換え書き換え"
app.saveContext()
}
println("------------ Yes Data")
}else {
println("No Data")
}
}
//
func initMasterBlogData() {
let blogPath:NSString = NSBundle.mainBundle().pathForResource("BlogData", ofType: "plist")!
var blogDataDictionary:NSDictionary = NSDictionary(contentsOfFile: blogPath as String)!
let app: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let blogContext:NSManagedObjectContext = app.managedObjectContext!
for(var i = 1; i<=blogDataDictionary.count; i++) {
let index_name: String = "Blog" + String(i)
var item: AnyObject = blogDataDictionary[index_name]!
let blogEntity: NSEntityDescription! = NSEntityDescription.entityForName(
"Blog",
inManagedObjectContext: blogContext
)
var new_data = NSManagedObject(entity: blogEntity, insertIntoManagedObjectContext: blogContext)
new_data.setValue(item["title"] as! String, forKey: "title")
new_data.setValue(item["uuid"] as! NSNumber, forKey: "uuid")
var error: NSError?
blogContext.save(&error)
}
}
func initMasterArticleData() {
let articlePath:NSString = NSBundle.mainBundle().pathForResource("ArticleData", ofType: "plist")!
var articleDataDictionary:NSDictionary = NSDictionary(contentsOfFile: articlePath as String)!
let app: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let articleContext:NSManagedObjectContext = app.managedObjectContext!
for(var i = 1; i<=articleDataDictionary.count; i++) {
let index_name: String = "Article" + String(i)
var item: AnyObject = articleDataDictionary[index_name]!
let articleEntity: NSEntityDescription! = NSEntityDescription.entityForName(
"Article",
inManagedObjectContext: articleContext
)
var new_data = NSManagedObject(entity: articleEntity, insertIntoManagedObjectContext: articleContext)
new_data.setValue(item["title"] as! String, forKey: "title")
new_data.setValue(item["body"] as! String, forKey: "body")
var error: NSError?
articleContext.save(&error)
}
}
//
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}