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).有点绕,但我能想到的替代方案并没有那么简单。
以下代码只是一个例子:
我需要在我的 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).有点绕,但我能想到的替代方案并没有那么简单。