在SwiftUI视图中实现委托

L. *_*han 6 delegates swift swiftui

我正在尝试实现需要委托方法(如NSUserActivity)的功能。因此,我需要一个UIViewController符合NSUserActivityDelegate(或类似的其他代表),处理并保存所有必需信息的。我的问题是我在界面上使用的是SwiftUI,因此我没有使用UIViewControllers。因此,我该如何实现此功能,同时仍将SwiftUI用于UI。我尝试了什么:view1只是一个普通的SwiftUI View,可以(通过NavigationLink)呈现view2,这是要实现此功能的视图。因此,我尝试了以下方法,而不是链接view1和view2,而是将view1链接到UIViewControllerRepresentable,然后处理该功能的实现并添加UIHostingController(rootView: view2)为子视图控制器。

struct view1: View {    
    var body: some View {
        NavigationLink(destination: VCRepresentable()) {
            Text("Some Label")
        }
    }
}

struct view2: View {    
    var body: some View {
        Text("Hello World!")
    }
}

struct VCRepresentable: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> UIViewController {
        return implementationVC()
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) { }
}

class implementationVC: UIViewController, SomeDelegate for functionality {
    // does implementation stuff in delegate methods
    ...

    override func viewDidLoad() {
        super.viewDidLoad()

        attachChild(UIHostingController(rootView: view2()))
    }

    private func attachChild(_ viewController: UIViewController) {
        addChild(viewController)

        if let subview = viewController.view {
            subview.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(subview)

            subview.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
            subview.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
            subview.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
            subview.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        }

        viewController.didMove(toParent: self)
    }
}
Run Code Online (Sandbox Code Playgroud)

我在VC和view2之间传输数据时遇到麻烦。所以我想知道是否有更好的方法在SwiftUI视图中实现这样的功能。

RPa*_*l99 22

您需要创建一个符合UIViewControllerRepresentable并具有Coordinator处理所有委托功能的视图。

例如,使用您的示例视图控制器和委托:

struct SomeDelegateObserver: UIViewControllerRepresentable {
    let vc = SomeViewController()
    var foo: (Data) -> Void
    func makeUIViewController(context: Context) -> SomeViewController {
        return vc
    }

    func updateUIViewController(_ uiViewController: SomeViewController, context: Context) { }
    func makeCoordinator() -> Coordinator {
        Coordinator(vc: vc, foo: foo)
    }

    class Coordinator: NSObject, SomeDelegate {
        var foo: (Data) -> Void
        init(vc: SomeViewController, foo: @escaping (Data) -> Void) {
            self.foo = foo
            super.init()
            vc.delegate = self
        }
        func someDelegateFunction(data: Data) {
            foo(data)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

struct ContentView: View {
    var dataModel: DataModel

    var body: some View {
        NavigationLink(destination: CustomView(numberFromPreviousView: 10)) {
            Text("Go to VCRepresentable")
        }
    }
}

struct CustomView: View {
    @State var instanceData1: String = ""
    @State var instanceData2: Data?
    var numberFromPreviousView: Int // example of data passed from the previous view to this view, the one that can react to the delegate's functions
    var body: some View {
        ZStack {
            SomeDelegateObserver { data in
                print("Some delegate function was executed.")
                self.instanceData1 = "Executed!"
                self.instanceData2 = data
            }
            VStack {
                Text("This is the UI")
                Text("That, in UIKit, you would have in the UIViewController")
                Text("That conforms to whatever delegate")
                Text("SomeDelegateObserver is observing.")
                Spacer()
                Text(instanceData1)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:我重命名VCRepresentableSomeDelegateObserver更能说明它的作用:它的唯一目的是等待委托函数执行,然后运行foo您提供的闭包(即在此示例中)。您可以使用此模式创建尽可能多的函数以“观察”您关心的任何委托函数,然后执行可以更新 UI、数据模型等的代码。在我的示例中,当SomeDelegatefires 时someDelegateFunction(data:),视图将显示“已执行”并更新数据实例变量。

  • 很高兴你想出来了!我会将“UIViewController”重命名为更通用;视图控制器应该是委托所属的任何类型的视图控制器。例如,如果您想监听 tableview 委托方法,您可以将视图控制器设为“TableViewController”,或者将结构设为“UIViewRepresentable”并使用“TableView”,然后将其委托挂接到协调器中。 (2认同)
  • 为了更好地理解“Coordinator”,这里有一个关于它的很棒的教程:https://www.hackingwithswift.com/books/ios-swiftui/using-coordinators-to-manage-swiftui-view-controllers (2认同)