UIViewControllerRepresentable 是否有理由永远不应该是一个类?

问题描述

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

import protocol SwiftUI.UIViewControllerRepresentable

一般来说,您将不得不涉及一个委托对象:充其量 an AnyObject,通常,因为 UIKit API 很旧,NSObject

常见的模式是为此使用一个 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()
  }
}

解决方法

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

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

就您而言,每当您更新 View 时,不仅会重新创建您的视图,还会重新创建您的两个主题,因此在重新创建后附加到 Publisher 的任何内容都不会收到事件没有了。

也许这就是我们更喜欢使用 Coordinator 的原因。