It doesn't seem to be possible to pass a writable key path for a variable that was declared inside an unamed closure or inside a playground. Or am I missing something
Binding is wonderful, but it's overkill and doesn't solve your problem directly. We never got a simpler, more usable variant in the standard library, that isn't SwiftUI-related. Here's mine:
/// A workaround for limitations of Swift's computed properties.
///
/// Limitations of Swift's computed property accessors:
/// 1. They are not mutable.
/// 2. They cannot be referenced as closures.
@propertyWrapper public struct Computed<Value> {
public typealias Get = () -> Value
public typealias Set = (Value) -> Void
public init(
get: @escaping Get,
set: @escaping Set
) {
self.get = get
self.set = set
}
public var get: Get
public var set: Set
public var wrappedValue: Value {
get { get() }
set { set(newValue) }
}
public var projectedValue: Self {
get { self }
set { self = newValue }
}
}
//MARK:- public
public extension Computed {
init(
wrappedValue: Value,
get: @escaping Get = {
fatalError("`get` must be assigned before accessing `wrappedValue`.")
},
set: @escaping Set
) {
self.init(get: get, set: set)
self.wrappedValue = wrappedValue
}
}
struct Structure {
private(set) static var value: Int = 0
@Computed( set: { value = $0 } ) var property = 1
}
var value: Int = .random
var instance = Structure()
XCTAssertEqual(Structure.value, 1)
instance.$property = .init
{ value }
set: { value = $0 }
instance.property = 2
XCTAssertEqual(value, 2)
instance.$property.get = { 3 }
XCTAssertEqual(instance.property, 3)
instance.$property.set = { _ in }
instance.property = 4
XCTAssertNotEqual(4, value)
Similar, for observers:
/// A workaround for limitations of Swift's observed properties.
///
/// Limitations of Swift's property observers:
/// 1. They are not mutable.
/// 2. They cannot be referenced as closures.
@propertyWrapper public struct Observed<Value> {
public typealias WillSet = (_ newValue: Value) -> Void
public typealias DidSet = (
_ oldValue: Value,
_ value: inout Value
) -> Void
public var willSet: WillSet
public var didSet: DidSet
public var wrappedValue: Value {
willSet { willSet(newValue) }
didSet { didSet(oldValue, &wrappedValue) }
}
public var projectedValue: Self {
get { self }
set { self = newValue }
}
}
//MARK:- public
public extension Observed {
init(
wrappedValue: Value,
willSet: @escaping WillSet = { _ in },
didSet: @escaping DidSet = { _, _ in }
) {
self.wrappedValue = wrappedValue
self.willSet = willSet
self.didSet = didSet
}
}