带有 MVVM + Realm 数据库的 SwiftUI:如何创建包含元素的列表?

SwiftUI with MVVM + Realm database: How to create a list with elements?

我想在我的 SwiftUI 应用程序中使用领域数据库,并且我想应用 MVVM 模式。不幸的是,当我使用数据库中的元素创建列表时,我收到 Fatal error: Unexpectedly found nil while unwrapping an Optional value: 错误消息

数据库管理器:

class DatabaseManager{

    private let realm: Realm
    public static let sharedInstance = DatabaseManager()

    private init(){
        realm = try! Realm()
    } 

    func fetchData<T: Object>(type: T.Type) -> Results<T>{
        let results: Results<T> = Realm.objects(type)
        return results
    }
}

型号:

class FlashcardDeck: Object, Codable, Identifiable{
    @objc private (set) dynamic var id = NSUUID().uuidString
    @objc dynamic var title: String?
    var cards = RealmSwift.List<Flashcard>()

    convenience init(title: String?, cards: [Flashcard]){
        self.init()
        self.title = title
        self.cards.append(objectsIn: cards)
    }
    
    override class func primaryKey() -> String? {
        return "id"
    }
}

ViewModel

class FlashcardDeckViewModel: ObservableObject{
    let realm = DatabaseManager.sharedInstance
    @Published var decks: Results<FlashcardDeck>?

    public func fetchDecks(){
        decks = realm.fetchData(type: FlashcardDeck.self)
    } 
}

查看

struct FlashcardDeckView: View {
    private let gridItems = [GridItem(.flexible())]
    @StateObject var viewModel = FlashcardDeckViewModel()

    var body: some View {
        NavigationView{
            ScrollView{
                LazyVGrid(columns: gridItems, spacing: 30){
                    ForEach(viewModel.decks!) { item in // <----- ERROR APPEARS HERE
                        FlashcardDeckItem(deck: item)
                    }
                }
            }
            .navigationTitle("Flashcard decks")
        }
        .onAppear{
            self.viewModel.fetchDecks()
            print(self.viewModel.cards?[0].title) // <------ prints the title of the deck! So this element exists
        }
    }
}

我很确定我的数据库有一个元素,如果我尝试在 fetchData() 函数中打印牌组的名称,它就会显示出来。我知道 ForEach(viewModel.decks!) 行不是漂亮的代码,但这仅适用于 testing/debugging 现在。

有条件地包含它,例如

    NavigationView{
      if viewModel.decks == nil {
        Text("Loading...")
      } else {
        ScrollView{
            LazyVGrid(columns: gridItems, spacing: 30){
                ForEach(viewModel.decks!) { item in // <----- ERROR APPEARS HERE
                    FlashcardDeckItem(deck: item)
                }
            }
        }
        .navigationTitle("Flashcard decks")
      }
    }