RealmSwiftに対応したModelをObjectMapperを使って実装しています。
以下の状態で、Realmの「Object」を継承しなければObjectMapperによってインスタンスを生成できます。
Swift
1import Foundation 2import ObjectMapper 3import RealmSwift 4 5class Question: Mappable { 6 7 dynamic var id: Int = 0 8 dynamic var title: String = "" 9 dynamic var body: String = "" 10 dynamic var created: Double = 0 11 dynamic var modified: Double = 0 12 dynamic var count_reply: Int = 0 13 dynamic var count_pv: Int = 0 14 15 class func newInstance(map: Map) -> Mappable? { 16 return Question() 17 } 18 19 required convenience init?(_ map: Map){ 20 self.init() 21 } 22 23 func mapping(map: Map) { 24 id <- map["id"] 25 title <- map["title"] 26 body <- map["body"] 27 created <- map["created"] 28 modified <- map["modified"] 29 count_reply <- map["count_reply"] 30 count_pv <- map["count_pv"] 31 } 32} 33
しかし
Swift
1class Question: Object, Mappable { 2 中略 3}
とした時に必ずRLMExceptionになってしまい、落ちてしまいます。
エラー内容は以下です。
txt
1Terminating app due to uncaught exception 'RLMException', reason: ''NSArray' is not supported as an RLMObject property. All properties must be primitives, NSString, NSDate, NSData, RLMArray, or subclasses of RLMObject. See http://realm.io/docs/objc/api/Classes/RLMObject.html for more information.'
NSArrayではダメだとかいてあるのですが、RealmSwift公式ドキュメントでは以下のようにDictionaryで渡しています。
swift
1// (2) Dictionaryの値を使ってDogクラスのオブジェクトを作成する 2let myOtherDog = Dog(value: ["name" : "Pluto", "age": 3])
また私のコード上では以下のようにしてインスタンスを生成しています。
swift
1let questions = json["questions"].arrayObject 2 3for subJson in questions! { 4 let question: Question = Mapper<Question>().map(subJson)! 5 self.questions.append(question) 6}
Clip Model
Swift
1class Clip: Object, Mappable { 2 3 // MARK: Realm - stored properties 4 5 dynamic var id: Int = 0 6 dynamic var title: String = "" 7 dynamic var created: Double = 0 8 dynamic var modified: Double = 0 9 dynamic var count_reply: Int = 0 10 dynamic var count_pv: Int = 0 11 dynamic var is_beginner: Bool = false 12 dynamic var is_accepted: Bool = false 13 dynamic var is_presentation: Bool = false 14 dynamic var tags: [String] = [] 15 var user: User = User() 16 var replies = List<Reply>() 17 18 // MARK: ObjectMapper 19 20 class func newInstance(map: Map) -> Mappable? { 21 return Clip() 22 } 23 24 required convenience init?(_ map: Map){ 25 self.init() 26 } 27 28 /// Mapping between ObjectMapper (JSON) and the model properties 29 func mapping(map: Map) { 30 id <- map["id"] 31 title <- map["title"] 32 created <- map["created"] 33 modified <- map["modified"] 34 count_reply <- map["count_reply"] 35 count_pv <- map["count_pv"] 36 is_beginner <- map["is_beginner"] 37 is_accepted <- map["is_accepted"] 38 is_presentation <- map["is_presentation"] 39 tags <- map["tags"] 40 user <- map["user"] 41 replies <- map["replies"] 42 } 43}
このRealmモデルは下記のGistを参考に作りました。
Transform arrays with ObjectMapper to Realm's List type
なぜうまくいかないのかお分かりになる方がいればよろしくお願いします。
私の環境では、上記のモデルに対して、`let question = Mapper<Question>().map(string)`などとして、Questionのインスタンスを作成することができましたが、どのような例外が起こっているのでしょうか?ちなみに、Realmに保存したモデルからJSONに変換するのはObjectMapperでは多少問題があります。
遅くなって申し訳ありません。
訂正依頼ありがとうございます。
追記いたしました。
その例外は、Realmが初期化時の最初の一回、モデルの構造を読み込んでいる最中に出るもので、モデルのプロパティにNSArrayは使用できないということを示しています。本当に定義しているモデルは上記で合っていますか?また、他のモデルでNSArrayをプロパティにしているものがありませんか?おそらく、Questionクラスには問題がないのですが、他のクラスにRealmのモデルとして正しくない定義のものがあり、QuestionをObjectのサブクラスにするとRealmの初期化が動作するので、その別のモデルクラスがエラーになってるのではないかと推測しています。
なるほどです。全く理解できていませんでした・・
他のモデルのプロパティにNSArrayがあります。この場合何で置き換えるのが妥当なのでしょうか。ドキュメントにはListがArrayの代わりになるが、RLMオブジェクトのサブクラスしか格納できないと記載されているのですが、格納したいデータを一旦RLMオブジェクト化するのが最適な方法でしょうか。
> 一旦RLMオブジェクト化するのが最適な方法でしょうか たいていはそうなります。最適なデータモデリングというのはケースバイケースなので、差し支えなければ、その他のモデルの定義も載せてもらえませんか?察するにteratailのAPIレスポンスをモデリングしようとしてるのですよね?
おっしゃる通りのことを実装しようとしています。おそらくこちらのタグを[String]で定義している部分でハマっているのだと思います。
この場合は、Tagのモデルを定義して、それの関連にするのがいいと思います。`class Tag: Object {
dynamic var tagName = ""
dynamic var explain = ""
dynamic var created = NSDate()
}`で、プロパティの方は`let tags: List<Tag>`ですね。APIによってタグの構造全部を返すものと名前だけ返すものがあるようですが、名前だけ返すものについては名前で検索して、保存済みのTagがあればそれを、なければ`explain`と`created`は空で名前だけの`Tag`を作って、後でタグのAPIを叩く機会があった時に更新するようにすると良いと思います。
詳しくありがとうございます!実装し終わりましたらまたここにレスをさせていただきます。
ご指導いただいた通りに変更しましたところきちんとインスタンス化することができました。詳しいご説明ありがとうございました。
ベストアンサーに選びたいのですが、この欄への投稿をコピペして回答欄に入力していただけるとありがたいです。
回答2件
あなたの回答
tips
プレビュー