LoginSignup
6
2

SwiftDataの@Modelを付けたクラスにStructやEnumを含めたい

Last updated at Posted at 2023-08-31

待ちに待ったSwiftDataをアプリで使えないかと調べていたところ、躓きそうな箇所があったのでメモ。

問題

SwiftDataの@ModelをつけたクラスにStructやEnumを置くとエラーが発生する。
このエラーNo exact matches in call to instance methodとしか言われないので原因がかなりわかりづらい。

import SwiftData

struct Location {
    let latitude: Double
    let longitude: Double
}

@Model
final class Home {
    let location: Location // エラー!!!
    
    init(location: Location) {
        self.location = location
    }
}

解決方法

プロパティに含めたいStructやEnumをCodableに準拠させる。

Structの場合

単にCodableに準拠させればOK。

struct Location: Codable {
    let latitude: Double
    let longitude: Double
}

@Model
final class Home {
    let location: Location
    
    init(location: Location) {
        self.location = location
    }
}

Enumの場合

IntでもStringでも値型なEnumをCodableに準拠させればOK。

enum ChocolateType: Int, Codable {
    case white
    case milk
    case sweet
    case bitter
}

@Model
final class Chocolate {
    var name: String
    var type: ChocolateType
    
    init(name: String, type: ChocolateType) {
        self.name = name
        self.type = type
    }
}

解説

WWDC2023のMeet SwiftDataの2分あたりでサラッと複雑な値型はCodableに準拠することで使えると話している。

実際に@Modelを付けると準拠されるPersistentModelのリファレンスから、エラーが発生しているgetValue(forKey:)について調べると、以下のいずれかに準拠した値が取得できるとわかる。

  • PersistentModel
  • RelationshipCollection
  • Decodable

また同様にエラーが発生するsetValue(forKey:)にもEncodableの制約がついたものがある。
よってPersistentModelは@Modelを付けたクラスであり、RelationshipCollectionは名前からしてリレーション用だと思われるので、その他の@Model内で定義される変数はCodableに準拠することで値を格納・取得できるようにしていると考えられる。

getValue(forKey:)

func getValue<Value>(forKey: KeyPath<Self, Value>) -> Value where Value : Decodable

setValue(forKey:)

func setValue<Value>(
    forKey: KeyPath<Self, Value>,
    to newValue: Value
) where Value : Encodable

以下憶測だが、これを踏まえるとSwiftDataの@Attribute(originalName:)を使うこととプロパティ名とスキーマでの名前を分けられるが、内部ではCodableのCodingKeysを使って実現しているのではないかと考えられる。

参考文献

6
2
0

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
6
2