iosswiftswiftuiswift-data

Swift - Accessing an array inside a swift class causes a crash in SwiftData


I'm using Swift and SwiftData. I have a class called Story and inside that class an array of another class called StoryBox.

I instantiate a Story with a StoryBox array and pass it to a view and try to display its content.

I can display the String of the Story object but if I add the lines to try to access the contents of the any element of the StoryBox array inside it I get an error stating:

"Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1c3c6203c)" on the

return self.getValue(forKey: \.storyBoxArray)

This is autogenerated code from the SwiftData implementation.

Error in Xcode when loading view

Classes:

Story:

import SwiftUI
import SwiftData

@Model
class Story{
    
    let id = UUID()
    var storyTitle: String
    var storyTitleImage: Data
    var storyBoxArray: [StoryBox]
    
    
    init(storyTitle: String, storyTitleImage: Data, storyBoxArray: [StoryBox]) {
        self.storyTitle = storyTitle
        self.storyTitleImage = storyTitleImage
        self.storyBoxArray = storyBoxArray
    }

}

StoryBox:

import SwiftUI
import SwiftData

@Model
class StoryBox {
    
    let id = UUID()
    var storyImage: Data
    var storyIndex: Int
    var storyIsCompleted: Bool
    var storyText: String
    
    init(storyImage: Data, storyIndex: Int, storyIsCompleted: Bool, storyText: String) {
        self.storyImage = storyImage
        self.storyIndex = storyIndex
        self.storyIsCompleted = storyIsCompleted
        self.storyText = storyText
    }
}

View:

import SwiftUI
import SwiftData

struct TempNewView: View {
    @State var CurrentStory: Story
    var body: some View {
        Text("\(CurrentStory.storyTitle)")
        let myImage = UIImage(data: CurrentStory.storyTitleImage)
        Image(uiImage: myImage!)

        let myImage2 = UIImage(data: CurrentStory.storyBoxArray[0].storyImage)
        Image(uiImage: myImage2!)
        
    }
}

The error occurs when I try to access the Data here:

let myImage2 = UIImage(data: CurrentStory.storyBoxArray[0].storyImage)
    Image(uiImage: myImage2!)

It also crashes the Preview.

Any ideas?

EDIT:

This is the call for the view

TempNewView(CurrentStory: Story(storyTitle: "Story Title_Preview", storyTitleImage: (UIImage(systemName: "5.lane")?.pngData())!, storyBoxArray: preview_createStoryBoxes(number: 6)))

This is the method which generates the array of StoryBox

func preview_createStoryBoxes(number: Int)->[StoryBox]{
var StoryData = [StoryBox]()
for i in 0...number {
    StoryData.append(StoryBox(storyImage: UIImage(systemName: "\(i).circle")!.pngData()!, storyIndex: i, storyIsCompleted: false, storyText: "\(i): The quick fox jumps over the lazy dog"))
}
return StoryData

}


Solution

  • SwiftData is a bit sensitive to how you create objects and relationship, specially when all objects are new. The safest way I found is to create an object that is part of the relationship, insert it into the model context and then assign the object(s) that is the other part of the relationship.

    So the line

    TempNewView(CurrentStory: Story(storyTitle: "Story Title_Preview", storyTitleImage: (UIImage(systemName: "5.lane")?.pngData())!, storyBoxArray: preview_createStoryBoxes(number: 6)))
    

    should be split up into

    let story = Story(storyTitle: "Story Title_Preview", storyTitleImage: (UIImage(systemName: "5.lane")?.pngData())!, storyBoxArray: [])
    
    modelContext.insert(story)
    story.storyBoxArray = preview_createStoryBoxes(number: 6))) //or use append
    

    And then call the view with story