-
-
Save Amzd/c3015c7e938076fc1e39319403c62950 to your computer and use it in GitHub Desktop.
extension Binding { | |
/// Wrapper to listen to didSet of Binding | |
func didSet(_ didSet: @escaping ((newValue: Value, oldValue: Value)) -> Void) -> Binding<Value> { | |
return .init(get: { self.wrappedValue }, set: { newValue in | |
let oldValue = self.wrappedValue | |
self.wrappedValue = newValue | |
didSet((newValue, oldValue)) | |
}) | |
} | |
/// Wrapper to listen to willSet of Binding | |
func willSet(_ willSet: @escaping ((newValue: Value, oldValue: Value)) -> Void) -> Binding<Value> { | |
return .init(get: { self.wrappedValue }, set: { newValue in | |
willSet((newValue, self.wrappedValue)) | |
self.wrappedValue = newValue | |
}) | |
} | |
} |
struct FilterView: View { | |
@Binding var filters: [String] | |
@Binding var selectedFilters: Set<String> | |
var body: some View { | |
List(filters, id: \.self, selection: $selectedFilters.didSet { | |
print("Selection changed from \($1) to \($0)") | |
}, rowContent: { filter in | |
Text(filter) | |
}) | |
} | |
} |
Thanks for putting this out there, but I found a simpler code layout that can do this
You just renamed the function? xd
@discardableResult
makes no sense because if you discard the new binding the handler won't get called..
@discardableResult makes no sense because if you discard the new binding the handler won't get called..
Well, it'll be called. So, in the onAppear
modifier for a SwiftUI widget I register the handler. Here's how I used it:
...someSwiftUIView
.onAppear {
self.$error.onChange { newValue in
someOtherProperty = newValue
}
}
In any case, the @discardableResult
doesn't mean the returned object won't be used, it simply means in case the call site doesn't assign it, then let Xcode know and stop worrying.
Does that make sense?
I don't think that works, you don't use the new returned Binding there? Am I missing how this works?
So, look at the code again, it's very similar to your code--it returns a Binding<Value>
which can be used, like in your example. But, in my case, with the .onAppear...
hook, I just wanted to be able to execute an action whenever the @Binding
variable's value changes. The error
variable is already declared, like so:
@Binding var error: Error
I needed to (imperatively) update some other property whenever a new value is sent to the already-declared variable. So, that's why you see the .onAppear
set up.
Meanwhile, here's where I got the code from: https://www.hackingwithswift.com/quick-start/swiftui/how-to-run-some-code-when-state-changes-using-onchange
Also, like I mentioned previously, the @discardableResult
annotation is only to inform Xcode (and the compiler) that it's fine if the returned value isn't assigned to some other symbol. It doesn't actually prevent the extension function from returning the value. See: https://www.avanderlee.com/swift/discardableresult/ and https://www.hackingwithswift.com/example-code/language/how-to-ignore-return-values-using-discardableresult
You may test it and see for yourself.
I know what @discardableResult
does. I don't really understand how you think your code would work, like how does the original binding know about your handler closure?..
I tested it because you were very confident, it doesn't work.
@Amzd my apologies. Yeah, using the extension function in the .onAppear()
hook doesn't work, true. But it still works as in the original use case you provided: ...selection: $selectedFilters.onChange...
In any case, the original intention was to offer a more concise version of the code as the one you created.
Hi there. Thanks for putting this out there, but I found a simpler code layout that can do this:
You can then use the above like so:
Admittedly, this doesn't offer you access to the previous value in the setter like your code does.