I'm trying to pass a binding to a variable that is created with a property wrapper. It appears that I lose access to the underlying type, when I pass the binding to another view. In the following example code, I demonstrate that I can update the original bound value, but not when I pass its binding to another view:
import SwiftUI
@propertyWrapper
struct BoundedNumber {
private var number: Int
private var minimum: Int
private var maximum: Int
init(wrappedValue: Int, minimum: Int, maximum: Int) {
self.minimum = minimum
self.maximum = maximum
number = max(minimum, min(wrappedValue, maximum))
}
var wrappedValue: Int {
get { return number }
set { number = max(minimum, min(newValue, maximum)) }
}
}
struct ContentView: View {
@State @BoundedNumber(minimum: 0, maximum: 10) var firstNumber: Int = 1
@State @BoundedNumber(minimum: 1, maximum: 5) var secondNumber: Int = 1
var body: some View {
VStack {
HStack {
Text("\(firstNumber)")
UpdateButton($firstNumber, updateType: .decrement)
UpdateButton($firstNumber, updateType: .increment)
}
HStack {
Text("\(secondNumber)")
UpdateButton($secondNumber, updateType: .decrement)
UpdateButton($secondNumber, updateType: .increment)
}
Button {
firstNumber += 1 // This compiles
} label: {
Image(systemName: "plus")
}
}
}
}
struct UpdateButton: View {
@Binding var value: BoundedNumber
let updateType: UpdateType
init(_ value: Binding<BoundedNumber>, updateType: UpdateType) {
_value = value
self.updateType = updateType
}
enum UpdateType {
case increment, decrement
}
var body: some View {
Button {
value += updateType == .increment ? 1 : -1
// This gives a compiler error:
// Binary operator '+=' cannot be applied to operands of type 'BoundedNumber' and '_'
} label: {
Image(systemName: updateType == .increment ? "plus" : "minus")
}
}
}
Add the following extension with operator and your code worked. Tested with Xcode 12.4 / iOS 14.4
extension BoundedNumber {
static func +=(_ lhs: inout BoundedNumber, _ rhs: Int) {
lhs.wrappedValue += rhs
}
}