1

We are developing an iOS app using SwiftData. We have Bucket and BucketItem models where a Bucket can have many BucketItem, so there is a relationship between Bucket and BucketItem. Below is a simplified version of the models.

import Foundation
import SwiftData

@Model
class Bucket {
  var name: String
  var shared: Bool
  
  @Relationship(deleteRule: .cascade, inverse: \BucketItem.bucket) var items = [BucketItem]()
  
  init(name: String, shared: Bool) {
    self.name = name
    self.shared = shared
  }
}

import Foundation
import SwiftData

@Model
class BucketItem {
  var content: String
  var bucket: Bucket
  
  init(content: String, bucket: Bucket) {
    self.content = content
    self.bucket = bucket
  }
}

We show a list of Bucket with a count of how many BucketItem it has. This is working in the app on the device and simulator, however the relationship is not working on the Preview. Below is a simplified version of this component with the Preview configuration

import SwiftUI
import SwiftData

struct BucketsData: View {
 var bucket: Bucket //this is provided by a parent component that uses @Query to fetch the Buckets
  
  var body: some View {
    List {
      Section(bucket.name) {
        Text("Items: \(bucket.items.count)")
      }
      
    }
  }
}

#Preview {
  let config = ModelConfiguration(isStoredInMemoryOnly: true)
  let container = try! ModelContainer(for: Bucket.self, configurations: config)
  
  let testBucket = Bucket(name: "Test Bucket", shared: true)
  container.mainContext.insert(testBucket)
  
  let testItem = BucketItem(content: "Test Item", bucket: testBucket)
  container.mainContext.insert(testItem)
  
  return BucketsData(bucket: testBucket)
    .modelContainer(container)
}

The list show the "Test Bucket" with a count of 0 items. It appears that for some reason the items array is not getting populated with the related BucketItem. How can we fix this?

4
  • You insert testBucket twice and testItem zero times. Commented Jan 27, 2024 at 22:41
  • @Paulw11 you're right, I pasted the wrong version of the simplified component. I updated the example above. Commented Jan 27, 2024 at 23:44
  • 1
    You can fix this issue with a single character but I suspect you don't want to apply that fix. Make the bucket property optional in BucketItem and the preview will work fine without any other changes. I tried to find some other way to solve this but without success. Commented Jan 28, 2024 at 9:11
  • @JoakimDanielson it works, thank you. Actually I've seen another scenario where SwiftData works the way you would expect only if you set one side of the relationship as optional. It appears that for some reason SwiftData requires that to be fully functional, hopefully Apple will fix that in the future. Commented Jan 28, 2024 at 15:17

1 Answer 1

1

You can fix this by making BucketItem.bucket optional, like so:

@Model
class BucketItem {
  var content: String
  var bucket: Bucket?
  
    init(content: String, bucket: Bucket? = .none) {
    self.content = content
    self.bucket = bucket
  }
}

Why does this work? I don't know. SwiftData is weird.

Joakim Danielson already said it in the comments, but I'm posting this as an answer so people will know that this question is answered. I've tested this solution and it works.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.