-->

2020年5月3日日曜日

JSONデータを取り込んでRealmに保存する

プロジェクト内のJSONデータをRealmのモデルに変換して保存する。
xmlやplistを使うことも考えたが、codableを使うことで独自のモデルにも容易に対応させることができた。

環境


  • Xcode 11.4.1
  • Swift 5
  • iOS 13.4.1

StringやIntなどは自動Codableに準拠しているので、encodeやdecodeメソッドを使う必要はないが、
今回はその他のデータ型にも対応できるようにencode、decodeメソッドを実装した。

モデル[Recipe]

import Foundation
import RealmSwift

class Recipe: Object,Decodable {
    @objc dynamic var name =  ""
    @objc dynamic var category = ""
    @objc dynamic var country = ""
    @objc dynamic var season = ""
    var ingredients = List<Ingredient>() //RecipeとIngredientは1対多
    
    override static func primaryKey() -> String? {
        return "name"
    }
    
    private enum CodingKeys:String,CodingKey{
        case name
        case category
        case country
        case season
        case ingredients
    }
    required convenience public init(from decoder:Decoder) throws{
        self.init()
        let container = try decoder.container(keyedBy: CodingKeys.self)

        name = try container.decode(String.self, forKey: .name)
        category = try container.decode(String.self, forKey: .category)
        country = try container.decode(String.self, forKey: .country)
        season = try container.decode(String.self, forKey: .season)
        
        //一度配列に格納した後、Listに変換する
        let ingredientsArray = try container.decode([Ingredient].self, forKey: .ingredients)
        ingredients = ingredientsArray.reduce(List<Ingredient>()) {$0.append($1); return $0}
    }
}

モデル[ingredient]

import Foundation
import RealmSwift

class Ingredient: Object,Decodable {
    @objc dynamic var name = ""
    let recipes = LinkingObjects(fromType: Recipe.self, property: "ingredients")
    
    private enum CodingKeys: String, CodingKey {
         case name
     }
    
    required convenience public init(from decoder: Decoder) throws {
        self.init()
        let container = try decoder.container(keyedBy: CodingKeys.self)

        name = try container.decode(String.self, forKey: .name)

    }
}

JSONファイル

[
        {
        "name": "トマトパスタ",
        "category": "パスタ",
        "country": "イタリアン",
        "season": "Any",
        "ingredients":[
            {
                "name": "トマト"
            },
            {
                "name": "にんにく"
            }
        ]
        },
        {
        "name": "カツ丼",
        "category": "丼ぶり",
        "country": "和食",
        "season": "Any",
        "ingredients":[
            {
                "name": "たまねぎ"
            },
            {
                "name": "卵"
            },
            {
                "name": "豚肉"
            }
        ]
        },
        {
        "name": "ペペロンチーノ",
        "category": "パスタ",
        "country": "イタリアン",
        "season": "Any",
        "ingredients":[
            {
                "name": "にんにく"
            },
            {
                "name": "鷹の爪"
            }
        ]
        },
        {
        "name": "カレー",
        "category": "カレー",
        "country": "和食",
        "season": "Any",
        "ingredients":[
            {
                "name": "人参"
            },
            {
                "name": "たまねぎ"
            },
            {
                "name": "じゃがいも"
            },
            {
                "name": "牛肉"
            }
        ]
        },
        {
        "name": "シチュー",
        "category": "シチュー",
        "country": "和食",
        "season": "Any",
        "ingredients":[
            {
                "name": "人参"
            },
            {
                "name": "たまねぎ"
            },
            {
                "name": "じゃがいも"
            },
            {
                "name": "牛肉"
            }
        ]
        },
        {
        "name": "炒飯",
        "category": "ご飯",
        "country": "中華",
        "season": "Any",
        "ingredients":[
            {
                "name": "人参"
            },
            {
                "name": "たまねぎ"
            },
            {
                "name": "卵"
            },
            {
                "name": "にんにく"
            }
        ]
        },
        {
        "name": "炊き込みご飯",
        "category": "ご飯",
        "country": "和食",
        "season": "Any",
        "ingredients":[
            {
                "name": "人参"
            },
            {
                "name": "椎茸"
            },
            {
                "name": "鶏肉"
            },
            {
                "name": "大葉"
            }
        ]
        }
]

JSONデータの取り込み

        //JSONファイルのパスを取得
        guard let path = Bundle.main.path(forResource: "RecipesList", ofType: "json") else { return }
        let url = URL(fileURLWithPath: path)
        
        do {
            
            let realm = try! Realm()

            let data = try Data(contentsOf: url)
            let recipe_obj = try! JSONDecoder().decode([Recipe].self, from: data)

            try! realm.write {
                realm.deleteAll()
                realm.add(recipe_obj, update: true)
                
                //人参を使うレシピを取得・表示
                var objects: Results<Recipe>
                  objects = realm.objects(Recipe.self).filter("SUBQUERY(ingredients, $ingredient, $ingredient.name = %@).@count >= 1","人参")
                  print("objectsの中",objects)
            }
            
        } catch {
            print("エラー")
        }

参考にしたサイト

https://qiita.com/cottpan/items/4bb5ad8bce2e28c0220a

0 件のコメント:

コメントを投稿