ios 如何使用复杂模型设置SwiftData + SwiftUI应用程序?

bxjv4tth  于 2023-10-21  发布在  iOS
关注(0)|答案(1)|浏览(125)

我是Swift的初学者。我试图建立一个简单的DND字符表应用程序。这是我的简化角色模型。

@Model
final class Character {
    var name: String
    var hitDice: Dice

    init(name: String, hitDice: Dice) {
        self.name = name
        self.hitDice = hitDice
    }

}

class Dice {
    var number: Int
    var sides: Int

    init(_ number: Int, _ sides: Int) {
        self.number = number
        self.sides = sides
    }

}

当我构建应用程序时,我得到这个错误:No exact matches in call to instance method 'setValue'。这不仅仅发生在类上。字典也是如此。看起来像任何非原始类型。这是否与这些数据类型如何Map底层coredata/sqlite数据类型有关?
然后我把骰子变成模型

@Model
final class Dice {
     // ...
}

错误消失了,但我得到了这个神秘的断点

@Transient
private var _$backingData: any SwiftData.BackingData<Dice> = Dice.createBackingData()

public var persistentBackingData: any SwiftData.BackingData<Dice> {
    get {
        _$backingData
    }
    set {
        _$backingData = newValue
    }
}

static var schemaMetadata: [SwiftData.Schema.PropertyMetadata] {
  return [
    SwiftData.Schema.PropertyMetadata(name: "number", keypath: \Dice.number, defaultValue: nil, metadata: nil),
    SwiftData.Schema.PropertyMetadata(name: "sides", keypath: \Dice.sides, defaultValue: nil, metadata: nil)
  ]
}

init(backingData: any SwiftData.BackingData<Dice>) {
  _number = _SwiftDataNoType()
  _sides = _SwiftDataNoType()
  self.persistentBackingData = backingData
}

@Transient
private let _$observationRegistrar = Observation.ObservationRegistrar()

struct _SwiftDataNoType {
}

我的应用

import SwiftUI
import SwiftData

@main
struct CharacterSheetApp: App {
    let modelContainer: ModelContainer
    
    init() {
        do {
            modelContainer = try ModelContainer(for: Character.self)
        } catch {
            fatalError("Could not initialize ModelContainer")
        }
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(modelContainer)
    }
}

我做错了什么?

wkyowqbh

wkyowqbh1#

您已经将Character声明为@Model-这意味着该类的所有属性都需要能够存储在Swift Data中。简单类型,如字符串和整数不是问题。但是SwiftData不知道如何存储Dice对象。
当您将@Model添加到Dice时,该对象也可以存储。它不能直接存储在Character对象中,但是可以创建一个Dice对象,并且Character对象可以保存对 relatedDice的引用-这就是错误消失的原因。
我尝试了你的代码,一旦我将@Model添加到Dice,我就能够创建和获取Character,没有任何错误或异常。
关于数据设计的一个注意事项是,创建一个对象来存储Dice可能有点过分-您可能只是存储一个String,并在需要时解析它以创建骰子。例如,只需存储"2d20"或其他。
这是我的代码:

import Foundation
import SwiftData

@Model
final class Character {
    var name: String
    var hitDice: Dice

    init(name: String, hitDice: Dice) {
        self.name = name
        self.hitDice = hitDice
    }

}

@Model
class Dice {
    var number: Int
    var sides: Int

    init(_ number: Int, _ sides: Int) {
        self.number = number
        self.sides = sides
    }
}

struct ContentView: View {
    @Environment(\.modelContext) private var context
    @Query var allCharacters: [Character]
    var body: some View {
        VStack {
            List {
                ForEach(allCharacters) { char in
                    HStack {
                        Text("Name: \(char.name)")
                        Text("Dice: \(char.hitDice.number)d\(char.hitDice.sides)")
                    }
                }
                    
            }
            Button( action: {
                
                let char = Character(name: "Bob", hitDice: Dice(2, 20))
                context.insert(char)
                do {
                    try context.save()
                } catch {
                    print(error)
                }
            }) {
                Text("Make bob")
            }
        }
        .padding()
    }
}

struct CharacterSheet: App {
    let modelContainer: ModelContainer
    
    init() {
        do {
            modelContainer = try ModelContainer(for: Character.self)
        } catch {
            fatalError("Could not initialize ModelContainer")
        }
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(modelContainer)
    }
}

相关问题