I want to use a realm database in my SwiftUI app and I would like to apply the MVVM pattern. Unfortunately when I create a list with the elements in my database I get a Fatal error: Unexpectedly found nil while unwrapping an Optional value:
error message
DatabaseManager:
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
}
}
Model:
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)
}
}
View
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
}
}
}
I'm pretty sure that my database has an element and if I try to print the name of the deck in the fetchData()
function it will be displayed. I know the line ForEach(viewModel.decks!)
isn't beautiful code, but this is just for testing/debugging now.
Include it conditionally, like
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")
}
}