LoginSignup
40
39

More than 5 years have passed since last update.

Swift で Core Dataのリレーションシップ(1対多)を試す

Last updated at Posted at 2015-05-11

Swift のプロジェクトで CoreData でも1対多(リレーションシップ:relationship)の関係を持つデータを用意したいと思うことがあります。

CoreDataを操作するためだけのプロジェクトを用意

今回は(も?)、CoreData の操作だけのプロジェクトを用意しました(本当は、Playground で使えたら面白いんだけれど…)。

リレーションシップ(Relationship)の話に 登場するクラス

クラスの関係 としてBlog は、複数の Article を持つ状態になります

  • Blog
  • Article

リレーションシップ(1対多)を設定する

Blog側のリレーションシップ設定

スクリーンショット 2015-05-06 15.07.56.png

Article側のリレーションシップ設定

スクリーンショット 2015-05-11 22.21.38.png

クラスの設定

スクリーンショット 2015-05-11 22.25.23.png

各クラスのファイルを書き出す

  • 「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

全体のソース

データーの登録

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()
    }
}

40
39
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
39