Is it possible to create relationships between objects in previews?

Is it possible to create one-to-many relationships between optional objects in SwiftData Xcode Previews? The below code I call from #Preview crashes the canvas on the post.authors?.append(tempAuthors.randomElement()!) when I try to append an array to an optional array. I can append the previewAuthors array to the authors array in the simulator or on device, but it crashes in Preview. My running theory is it has something to do with being in memory since this works on device, but I'm not sure that I missed something super obvious.

static func previews(_ count: Int) -> [Post] {
        
        let previewAuthors = [Author(name: "..."), Author(name: "...")]
        
        var posts: [Post] = []

        for i in 0..<count {
        
            let post = Post(title: "Title \(i)")
            post.authors?.append(previewAuthors.randomElement()!)
            
            posts.append(post)
            
        }
        return posts
}
Answered by Developer Tools Engineer in 769663022

This should be possible, but you will want to create your model objects and insert them into your model context before you setup the relationship. Then make sure to save the context and use the parent container for your view. So creation would look something like:

static func previewPosts(_ count: Int, in context: ModelContext) -> [Post] {
    let previewAuthors = [Author(name: "..."), Author(name: "...")]
    for author in previewAuthors {
        context.insert(author)
    }

    var posts: [Post] = []
    for i in 0..<count {
        let post = Post(title: "Title \(i)")
        context.insert(post)

        post.authors?.append(previewAuthors.randomElement()!)
        posts.append(post)
    }

    try! context.save()

    return posts
}

and then your #Preview would look something like:

#Preview {
    let container = try! ModelContainer(for: Post.self, configurations: ModelConfiguration(isStoredInMemoryOnly: true))
    let context = container.mainContext
    let posts = previewPosts(5, in: context)

    PostsView(posts: posts)
        .modelContainer(container)
}
Accepted Answer

This should be possible, but you will want to create your model objects and insert them into your model context before you setup the relationship. Then make sure to save the context and use the parent container for your view. So creation would look something like:

static func previewPosts(_ count: Int, in context: ModelContext) -> [Post] {
    let previewAuthors = [Author(name: "..."), Author(name: "...")]
    for author in previewAuthors {
        context.insert(author)
    }

    var posts: [Post] = []
    for i in 0..<count {
        let post = Post(title: "Title \(i)")
        context.insert(post)

        post.authors?.append(previewAuthors.randomElement()!)
        posts.append(post)
    }

    try! context.save()

    return posts
}

and then your #Preview would look something like:

#Preview {
    let container = try! ModelContainer(for: Post.self, configurations: ModelConfiguration(isStoredInMemoryOnly: true))
    let context = container.mainContext
    let posts = previewPosts(5, in: context)

    PostsView(posts: posts)
        .modelContainer(container)
}

Thanks! That worked. I suspected I was overlooking something obvious, and it was that I forgot the context in Previews.

Is it possible to create relationships between objects in previews?
 
 
Q