2

I have been trying so many ways to resolve this issue. I am trying to fetch SwiftData records with a predicate. but everything I try results in a pair of errors:

initializer 'init(_:)' requires that 'Item' conform to 'Encodable'

initializer 'init(_:)' requires that 'Item' conform to 'Decodable'

The error is coming from within the expanded #Predicate macro.

Here is a bare bones class to demonstrate the issue:

@Model
final class Item {
    @Attribute(.unique) var id: String
    var timestamp: Date

    init(timestamp: Date) {
        self.id = UUID().uuidString
        self.timestamp = timestamp
    }
}

And here is the bare bones code that causes the compiler issue:

extension Item {
    static func foo() {
        let item = Item(timestamp: .now)
        let pred = #Predicate<Item> { $0.id == item.id }
    }
}

I've tried so many ways to resolve this error. None of the Apple SwiftData sample projects I've seen give this error.

I've tried conforming to Identifiable. I've renamed the id property. I've changed the id type to UUID directly instead of String.

And of course I've added code to conform to Codable. While that fixed the compiler error, I ended up getting a runtime error. Note that none of the Apple SwiftData projects conform their models to Codable.

What am I missing?

HangarRash
  • 7,314
  • 5
  • 5
  • 32

1 Answers1

5

The solution is to avoid referencing a model object inside the #Predicate closure.

Simply change the predicate line from:

let pred = #Predicate<Item> { $0.id == item.id }

to:

let anID = item.id
let pred = #Predicate<Item> { $0.id == anID }

While the solution seems trivial and obvious, the error can easily lead you down many wrong paths.

HangarRash
  • 7,314
  • 5
  • 5
  • 32
  • 1
    To add to this, the #Predicate macro seems to currently be very sensitive to what code that can be added. I got the same error from unwrapping an optional in a `guard` statement, using the coalescing operator ?? instead I could turn it into a one liner and the code compiled. – Joakim Danielson Jul 06 '23 at 20:54
  • Comparing to `nil` also seems to be problematic, so I had to make a dummy variable of the type I was comparing, set it to `nil`, and then compare on that. – eirikvaa Jul 22 '23 at 10:21