问题:在两个不相关的 ViewController(例如,在不同时间独立实例化的两个 ViewController)之间传递引用的最“Swiftian”方式是什么?
我正在编写一个 iOS 应用程序,它将有两个窗口:一个位于设备上,一个可选的外部窗口(例如通过 AirPlay 播放到电视或投影仪)。每个窗口都有自己的 SceneDelegate 和 ViewController。外部窗口在用户启动 AirPlay 时设置,或者在启动时设置(如果 AirPlay 已在运行)。这两种设置都是通过 Storyboard和 plist“自动”管理的。
挑战在于两个窗口都需要显示相同的实时摄像头信息。在我当前的实现中,主 ViewController 更新其自己的 View 和外部 View Controller 控制的 View 。
我认为主 ViewController 应该是外部 ViewController 的委托(delegate),但我不知道如何在两个 ViewController 之间传递必要的引用。这通常在转场期间完成,但外部 View 没有转场。
我当前的解决方案有效,但已经过时了。在 AppDelegate 中,我定义了对外部窗口中 UIImageView 的全局引用(如果存在):
class AppDelegate: UIResponder, UIApplicationDelegate {
var extImageView: UIImageView!
外部窗口的 ViewController 根据需要保持此引用最新:
class ExtViewController: UIViewController {
@IBOutlet var extImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.extImageView = extImageView
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.extImageView = nil
}
}
然后我在主 ViewController 中实现 AVCaptureVideoDataOutputSampleBufferDelegate 来更新外部窗口:
// MARK: - AVCaptureVideoDataOutputSampleBufferDelegate
extension CameraViewController: AVCaptureVideoDataOutputSampleBufferDelegate {
func captureOutput(_ captureOutput: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
let imageBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
let ciimage : CIImage = CIImage(cvPixelBuffer: imageBuffer)
let image : UIImage = self.convert(cmage: ciimage)
DispatchQueue.main.sync(execute: {() -> Void in
let appDelegate = UIApplication.shared.delegate as! AppDelegate
if let imageView = appDelegate.extImageView {imageView.image = image}
})
}
// Convert CIImage to CGImage
func convert(cmage:CIImage) -> UIImage
{
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(cmage, from: cmage.extent)!
let image:UIImage = UIImage.init(cgImage: cgImage, scale: 1.0, orientation: extOrientation)
return image
}
}
这是可行的,但代价是全局引用和非常具体的、可重用性较差的代码。是否有更优雅、可重用的方法,也许使用委托(delegate)?
最佳答案
实现关注点分离的直接解决方案是观察者模式,请检查以下使用发布通知技术重写代码以实现此目的:
class ExtViewController: UIViewController {
@IBOutlet var extImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
self.observeImageCaptureNotification()
}
func deint() {
self.removeAllObservers()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.extImageView = extImageView
}
func observeImageCaptureNotification() {
NotificationCenter.default.addObserver(self, selector: #selector(newImageDidCapture(notification:)), name: "NewImageDidCapture", object: nil)
}
func removeAllObservers() {
NotificationCenter.default.removeObserver(self)
}
@objc private func newImageDidCapture(notification: Notification) {
if let newImage = notification.userInfo?["image"] as? UIImage {
self.extImageView.image = newImage
}
}
}
// MARK: - AVCaptureVideoDataOutputSampleBufferDelegate
extension CameraViewController: AVCaptureVideoDataOutputSampleBufferDelegate {
func captureOutput(_ captureOutput: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
let imageBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
let ciimage : CIImage = CIImage(cvPixelBuffer: imageBuffer)
let image : UIImage = self.convert(cmage: ciimage)
DispatchQueue.main.sync(execute: {() -> Void in
NotificationCenter.default.post(name: Notification.Name(rawValue: "NewImageDidCapture"), object: nil, userInfo: ["image": image])
})
}
// Convert CIImage to CGImage
func convert(cmage:CIImage) -> UIImage
{
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(cmage, from: cmage.extent)!
let image:UIImage = UIImage.init(cgImage: cgImage, scale: 1.0, orientation: extOrientation)
return image
}
}
关于ios - 如何在主窗口和外部窗口的两个不相关 View Controller 之间传递引用(无segue,不同的SceneDelegate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59923590/