I'm having hard time understanding where multiple crashes are coming from this simple code.
typealias RepositoryData = Set<RepositoryItem> //RepositoryItem is a Sendable, struct
final class Repository {
private var data: RepositoryData
func save() {
let task = Task.detached { [weak self] in
try await Task.sleep(seconds: 1)
self?.data.save()
}
}
}
private extension Data {
func save() {
do {
let eventJSONData = try JSONEncoder().encode(self)
UserDefaults.standard.set(eventJSONData, forKey: "data")
} catch {}
}
}
I want to save data to UserDefaults after 1sec delay. Meanwhile, save
Task is sleeping, there are some operations that can happen on the data
itself (some added, some removed).
I cannot reproduce the issues, but in crash reports from production code I'm getting multiple different errors:
Attempted to dereference garbage pointer
countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x8000000000000000
-
NSInvalidArgumentException
countByEnumeratingWithState:objects:count
coming from this line:let eventJSONData = try JSONEncoder().encode(self)
According to what I found JSONEncoder
is Thread Safe and I cannot figure out why save()
method is called properly, but JSONEncoder
is crashing when accessing save()
- it's not the save()
method itself as all logs from this method are correctly visible. So data
exists when save()
is called, but then when Encoder comes in action it somehow gets deallocated.
What am I missing here?