【问题标题】:Implement delegates within SwiftUI Views在 SwiftUI 视图中实现委托
【发布时间】:2019-07-30 23:46:13
【问题描述】:

我正在尝试实现需要委托方法的功能(如NSUserActivity)。因此,我需要一个符合NSUserActivityDelegate(或类似的其他代表)的UIViewController,处理并保存所有必需的信息。我的问题是我的界面使用了 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)
    }
}

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

【问题讨论】:

  • 如果您的应用是SwiftUI 应用 - 听起来确实如此 - 那么您必须使用UIViewControllerRepresentable。没有它?您不能实现委托方法。现在,您可能会感到困惑 - UIHostingController 是您反向操作的方式...向您的 UIKit 项目添加一个 SwiftUI 视图。这里(以及其他地方,包括 WWDC 视频)有相当不错的在 SwiftUI 项目中使用 UIViewController 的示例。我的建议是 (1) 在 UIKit project first, then (2) expose it in a SwiftUI app - remember, a UIViewcontrollerRepresentable is just a SwiftUI View` 中工作。
  • 很抱歉,我更正了我的代码:view1 链接到 UIViewControllerRepresentable,以便将 UIViewController 添加到我的应用程序以处理我的委托。因为我想在 SwiftUI 中做我的 UI,所以这个 UIViewController 附加了一个子 vc(见代码),它是一个 UIHostingController,以便在 SwiftUI 视图中呈现 UI。我的问题是我无法真正在我的UIViewController(委托处理程序)和我的 SwiftUI View(view2)之间传递信息
  • UIHostingController 仅在 UIKit 应用程序中使用。这就是您将 SwiftUI View 带入 UIKit 的方式。基本上,您使用 either UIViewControllerRepresentable (UIKit >> SwiftUI) UIHostingController (SwiftUI >> UIKit。有关更多详细信息,请查看 Session 231: Integrating SwiftUI。
  • 好的,我明白了。但是我如何处理 UIViewController 上的委托方法而不将其用作 UI 而是使用 view2(快速 UI 视图)?
  • 我在我的 SwiftUI 项目中创建了三个 UIViewControllerRepresentables。 MTKView、UIImagePickerController 和 UIActivityViewController。其中两个使用委托(前两个)。我真的不确定他们是否能帮助你,但我愿意尝试。图像选择器背后的想法是 (a) 呈现它,(b) 使用委托方法来获取选择的图像或传递取消被按下的图像,以及 (c) 关闭它。它与我的模型相关联——从 beta 5 开始,它现在称为 ObservableObject,并在更新应用程序状态时更新各种 SwiftUI 视图。这对你有帮助吗?

标签: swift delegates swiftui


【解决方案1】:

您需要创建一个符合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)
        }
    }
}

用法:

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)
            }
        }
    }
}

注意:我将 VCRepresentable 重命名为 SomeDelegateObserver 以更能说明它的作用:它的唯一目的是等待委托函数执行然后运行闭包(即 @987654328 @ 在这个例子中)你提供它。您可以使用此模式创建任意数量的函数来“观察”您关心的任何委托函数,然后执行可以更新 UI、数据模型等的代码。在我的示例中,当 SomeDelegate 触发 @ 987654330@,视图将显示“已执行”并更新数据实例变量。

【讨论】:

  • 问题在于:NavigationLink 的目的地是 VCRepresentable,它在 UI 的 makeUIViewController(context:) 中返回 ImplementationVC,这需要我在 ImplementationVC 中执行我的 UI(所以使用 UIKit)
  • 不,您不需要这样做。您可以在 ZStack 中创建包含 VCRepresentable 和所需 UI 的自定义视图,然后导航到该视图。我将更新我的代码以向您展示我的意思。我猜 ImplementationVC 只是您的示例的占位符,而不是您项目中的实际视图控制器,对吧?
  • 对于SomeDelegate,我正在使用NSUserActivityDelegate,但不知何故我无法访问self.userActivity。当我使用class VC: UIViewController, NSUserActivityDelegate { ... } 时,我能够访问它。对于someDelegateFunction(data:),例如我也无法访问updateUserActivityState(_ activity:)
  • 很高兴你知道了!我将重命名UIViewController 更通用;视图控制器应该是委托所属的任何类型的视图控制器。例如,如果您想监听 tableview 委托方法,您可以将视图控制器设为 TableViewController 或将结构设为 UIViewRepresentable 并使用 TableView,然后将其委托连接到 Coordinator。
  • 为了更好地理解Coordinator,这里有一个很棒的教程:hackingwithswift.com/books/ios-swiftui/…
猜你喜欢
  • 1970-01-01
  • 2021-03-12
  • 2020-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-20
相关资源
最近更新 更多