Here we have yet another bug, I suppose, in SwiftData that happens on iOS18 but it is not an issue on iOS17.
There are 2 models defined as follows
@Model
final public class Note: Identifiable, Codable, Hashable
{
public private(set) var uuid = UUID().uuidString
var heading: String = ""
var tags: [Tag]?
init(heading: String = "") {
self.heading = heading
}
required public init(from decoder: Decoder) throws {
...
}
public func encode(to encoder: Encoder) throws {
...
}
}
@Model
final public class Tag: Identifiable, Codable
{
var name: String = ""
@Relationship(deleteRule: .nullify, inverse: \Note.tags) var notes: [Note]?
init(_ name: String) {
self.name = name
}
required public init(from decoder: Decoder) throws {
…
}
public func encode(to encoder: Encoder) throws {
...
}
}
and a function o add new tags as follows
private func addTags(note: Note, tagNames: [String]) {
if note.tags == nil {
note.tags = []
}
for tagName in tagNames {
if let tag = fetchTag(tagName) {
if !note.tags!.contains(where: {$0.name == tagName}) {
note.tags!.append(tag)
}
} else {
// The following line throws the exception on iOS18 when Tag conforms to Codable:
// Illegal attempt to map a relationship containing temporary objects to its identifiers.
note.tags!.append(Tag(tagName))
}
}
}
This code works perfectly well on iOS17 but on iOS18 I get the exception “Illegal attempt to map a relationship containing temporary objects to its identifiers.”
What I noticed that this happens only when Tag model conforms to Codable protocol. Is it a bug? It looks like, otherwise we've got some undocumented changes have been made.
In my previous post I mentioned about the other issue about ModelContext that is broken too on iOS18 - I mean it works perfectly well on iOS17.
Demo app with an example how to workaround this problem is available here on GitHub.
Repro steps:
- Add a note with some tags (separated by space)
- Edit this note and add a new tag (tag that does not exists in database) and tap Save.
You should noticed that the tag hasn't been added. It works occasionally but hardly to be seen.