Swift - 协议功能在另一个协议中的默认实现

Swift - Default Implementation of protocol functions in another protocol

以下代码只是一个例子: 我需要在我的 ViewController class 中实现 MapProtocol。 ViewController本身有一个MKMapView类型的变量。然而,在我的例子中,MKMapViewDelegate 需要通过协议的扩展来实现,而不能由 ViewController class 实现,但这是行不通的。根本不会调用委托函数(仅当由 ViewController 实现时)

我是否遗漏了 swift 在另一个协议中为协议添加默认实现的限制?如果是,是否有适当的解决方法?

真实案例场景: 我有两个 ViewController 共享一些冗余代码(MKMapViewDelegate 等)。所以我想外包这段代码。我不能使用 superclass 因为两个视图控制器已经是两种不同类型的 subclasses。我的第一个方法是使用扩展协议。

import UIKit
import MapKit

class ViewController: UIViewController, MapProtocol {

    var mapView: MKMapView = MKMapView()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        setupMapView()
    }

    private func setupMapView() {
        self.view.addSubview(mapView)

        mapView.mapType = MKMapType.standard
        mapView.isZoomEnabled = true
        mapView.isScrollEnabled = true
        mapView.delegate = self

        mapView.translatesAutoresizingMaskIntoConstraints = false
        mapView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0).isActive = true
        mapView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0).isActive = true
        mapView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true
        mapView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0).isActive = true
    }
}

/** Works if uncommented */
//extension ViewController: MKMapViewDelegate {
//    func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
//        NSLog("test")
//    }
//}

protocol MapProtocol: MKMapViewDelegate {
    var mapView: MKMapView { set get }
}

extension MapProtocol {
    func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
        NSLog("test")
    }
}

这有点奇怪,但我认为委托的分派查找不会 "see" 协议添加时的委托方法。协议扩展是静态绑定的,不是动态查找方案的一部分。

如果您认为 func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) 是一个 MKMapViewDelegate 协议方法,那就错了。它只是您创建的方法,而不是 MKMapViewDelegate 方法。

extension MapProtocol {

    func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
        NSLog("test")
    }
}

同样是您的委托方法未调用的原因。 viewController 收到回调,因为 mapView.delegate = self。这里没有MapProtocol的作用。

如果我理解正确,你要避免在不同的 viewcontroller 中重复 "map related code"。

在这种情况下,为什么不用 "data source" 方法,创建一个额外的 class ViewControllerMapInjector 或任何名称,并在初始化时传递 vc并执行您喜欢的任何方法

class ViewControllerMapInjector: MKMapViewDelegate {
    private let vc: UIViewController
    init(vc: UIViewController) {
       self.vc = vc
    }

    func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
        NSLog("test") // or use the vc as you want. 
    }
}

然后在 viewController setup() 只是

self.mapView.delegate = ViewControllerMapInjector(vc: self)

最终,您可能需要将其他模式应用于视图控制器,以便在需要时让提供者可以看到其他方法(最后,最简单的解决方案是完全面向对象和子class ViewController).有点绕,但我能想到的替代方案并没有那么简单。