I have run into a case with @ObservableDefault where modifying the value through the property wrapper results into the observer firing, which then writes the new value via the property wrapper, which once agains fires the observer, infinitely recursing.
I don't see any explicit logic to suppress this kind of recursion, and stepping through with a debugger it seems like even using a simpler type like Key<Int> calls results in the set {} block triggering the observation callback (ie, set {} -> observer -> set {}), but something in the underlying framework is suppressing the KVO callback.
There are some conditions under which it doesn't happen, so I wouldn't be surprised if there's some kind of pointer equality check within the underlying framework. Clearing the value out first seems to help reproduce.
Gist of crash.
Version: 9.0.5
Sources/TestObservableDefault/TestObservableDefault.swift
import Foundation
import Defaults
import DefaultsMacros
@main
struct TestObservableDefault {
static func main() {
Defaults[.testSet] = []
let observer = Observer()
observer.testSet.formUnion(1...10)
}
}
extension Defaults.Keys {
static let testSet = Key<Set<Int>>("int_set", default: [])
}
@Observable
final class Observer {
@ObservableDefault(.testSet)
@ObservationIgnored
var testSet: Set<Int>
init() {}
}
Package.swift
// swift-tools-version: 6.2
import PackageDescription
let package = Package(
name: "TestObservableDefault",
platforms: [
.macOS(.v26)
],
dependencies: [
.package(url: "https://github.com/sindresorhus/Defaults", .upToNextMajor(from: "9.0.0")),
],
targets: [
.executableTarget(
name: "TestObservableDefault",
dependencies: [
"Defaults",
.product(name: "DefaultsMacros", package: "Defaults")
]
),
],
)
I have run into a case with
@ObservableDefaultwhere modifying the value through the property wrapper results into the observer firing, which then writes the new value via the property wrapper, which once agains fires the observer, infinitely recursing.I don't see any explicit logic to suppress this kind of recursion, and stepping through with a debugger it seems like even using a simpler type like
Key<Int>calls results in theset {}block triggering the observation callback (ie,set {} -> observer -> set {}), but something in the underlying framework is suppressing the KVO callback.There are some conditions under which it doesn't happen, so I wouldn't be surprised if there's some kind of pointer equality check within the underlying framework. Clearing the value out first seems to help reproduce.
Gist of crash.
Version: 9.0.5
Sources/TestObservableDefault/TestObservableDefault.swift
Package.swift