1

假设您并不真正需要 SwiftUI 功能。即你import SwiftUI的文件中没有。相反,您只需要

import protocol SwiftUI.UIViewControllerRepresentable

通常,您将不得不涉及一个委托对象:充其量是一个AnyObjectNSObject,而且通常,因为 UIKit API 是旧的,一个.

常见的模式是为此使用一个Coordinator类,并让 View 本身成为一个结构,但是在那个间接性中总是有点吗?

这是一个在实践中没有给我带来任何麻烦的例子:

import Combine
import MultipeerConnectivity
import protocol SwiftUI.UIViewControllerRepresentable

extension MCBrowserViewController {
  final class View: NSObject {
    init(
      serviceType: String,
      session: MCSession,
      peerCountRange: ClosedRange<Int>? = nil
    ) {
      self.serviceType = serviceType
      self.session = session
      self.peerCountRange = peerCountRange
    }

    private let serviceType: String
    private unowned let session: MCSession
    private let peerCountRange: ClosedRange<Int>?

    private let didFinishSubject = CompletionSubject()
    private let wasCancelledSubject = CompletionSubject()
  }
}

// MARK: - internal
extension MCBrowserViewController.View {
  var didFinishPublisher: AnyPublisher<Void, Never> { didFinishSubject.eraseToAnyPublisher() }
  var wasCancelledPublisher: AnyPublisher<Void, Never> { wasCancelledSubject.eraseToAnyPublisher() }
}

// MARK: - private
private extension MCBrowserViewController {
  typealias CompletionSubject = PassthroughSubject<Void, Never>
}

// MARK: - UIViewControllerRepresentable
extension MCBrowserViewController.View: UIViewControllerRepresentable {
  func makeUIViewController(context: Context) -> MCBrowserViewController {
    let browser = MCBrowserViewController(
      serviceType: serviceType,
      session: session
    )

    browser.delegate = self

    if let peerCountRange = peerCountRange {
      browser.minimumNumberOfPeers = peerCountRange.lowerBound
      browser.maximumNumberOfPeers = peerCountRange.upperBound
    }

    return browser
  }

  func updateUIViewController(_: MCBrowserViewController, context _: Context) { }
}

// MARK: - MCBrowserViewControllerDelegate
extension MCBrowserViewController.View: MCBrowserViewControllerDelegate {
  func browserViewControllerDidFinish(_: MCBrowserViewController) {
    didFinishSubject.send()
  }

  func browserViewControllerWasCancelled(_: MCBrowserViewController) {
    wasCancelledSubject.send()
  }
}
4

1 回答 1

2

对于您的问题,我没有完整的详细答案,但是您的解决方案存在一些问题。

在 SwiftUI 中,如果我们更新 a View,它会调用init重新创建View,然后调用updateUIViewController.

在你的情况下,每当你更新你的View,不仅你的视图被重新创建,你的两个主题也将被重新创建,所以任何附加到Publisher游戏之后的东西都不会再收到事件。

也许这就是我们更喜欢使用Coordinator.

于 2020-12-22T17:31:54.360 回答