I am converting an iOS app from UIKit to SwiftUI. I have a UIViewController
that displays a view with different buttons. This UIViewController
has a delegate that conforms to a specific protocol. On each button's action, I call a method of its delegate. Nothing special here, it is a typical Delegate pattern as we all know for iOS development with UIKit.
My question is: Is it still a good approach with SwiftUI? I can totally convert this pattern in my SwiftUI app (I did already. EDIT: and as mentioned in comments, it is NOT a good idea!). But I'm wondering if this Delegate pattern is still a good way or if there is a different way to do that (with Binding maybe?). Is it recommended to use this pattern in a SwiftUI app?
Here is a simplified code example:
protocol MyCustomViewDelegate {
func buttonATapped()
}
struct MyCustomView: View {
public var delegate: MyCustomViewDelegate?
var body: some View {
Button("Button A") {
if let delegate = delegate {
delegate.buttonATapped()
}
}
}
}
struct ContentView: View, MyCustomViewDelegate {
var body: some View {
MyCustomView(delegate: self)
}
func buttonATapped() {
// Do something
}
}
EDIT: Please do not use this previous implementation!
CodePudding user response:
I think that if you use closures it is better, an example to pass the function:
struct MyCustomView: View {
var function: () -> Void
var body: some View {
Button(action: {
self.function()
}, label: {
Text("Button")
})
}
}
struct ContentView: View {
var body: some View {
ChildView(function: self.buttonATapped)
}
func buttonATapped() {
print("I am the parent")
}
}
CodePudding user response:
import SwiftUI
protocol MyCustomViewDelegate: ObservableObject {
func buttonATapped()
}
//I think of this as a vague UIViewController
class DelegateParentViewModel: ObservableObject{
@Published var tappedCount = 0
}
extension DelegateParentViewModel:MyCustomViewDelegate{
//@IBAction (ish)
func buttonATapped(){
tappedCount = 1
}
}
//I think of the View as a vague storyboard
struct DelegateParentView: View {
@StateObject var vm: DelegateParentViewModel = .init()
var body: some View {
VStack{
Text(vm.tappedCount.description)
DelegateChildView(vm: vm)
}
}
}
//I think of the View as a vague storyboard
struct DelegateChildView<T:MyCustomViewDelegate>: View {
@ObservedObject var vm: T
var body: some View {
Button("tap Button", action: {
//Call IBAction (ish)
vm.buttonATapped()
})
}
}
struct DelegateParentView_Previews: PreviewProvider {
static var previews: some View {
DelegateParentView()
}
}