我为协议添加了协议扩展,其关联类型为PickerType
。我写了一个函数refresh(:,completion:)
的重新实现,该函数在协议中定义并在其他协议扩展中实现。
但是,除非编译器知道refresh(:,completion:)
是什么类型,否则我在调用PickerType
时不会调用新扩展名内的函数。我写了以下内容:
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we're trying to have this implementation called")
PickerType.startSync()
}
}
如果我在refresh(:,completion:)
上调用PickerSectionProvider<ObservationType>
(如下面的Playground中的代码所示),就会像我期望的那样被调用,但是当我在{{1}上调用refresh(:,completion:)
时却不会},这是一种通用类型,必须符合ItemProvider
(再次参见下面的代码)。
PickerItemProvider
答案 0 :(得分:2)
请参阅以下更正的实现,
import Foundation
protocol PickerItemProvider: class {
associatedtype PickerType
func findItem(by identifier: NSNumber) -> PickerType?
func itemAt(_ indexPath: IndexPath) -> PickerType?
}
extension PickerItemProvider {
func findItem(by identifier: NSNumber) -> PickerType? {
return nil
}
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("the default refresh implementation")
}
}
public class PickerSectionProvider<ProvidedType: Equatable> : PickerItemProvider {
func itemAt(_ indexPath: IndexPath) -> ProvidedType? {
return nil
}
}
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we’re trying to have this implementation called instead of the above implementation of refresh")
PickerType.startSync()
}
}
protocol SyncableEntity {
static func startSync()
}
extension SyncableEntity {
static func startSync() {
}
}
class ObservationType: Equatable, SyncableEntity {
}
func ==(lhs: ObservationType, rhs: ObservationType) -> Bool {
return false
}
class GenericPickerViewController<PickerType: Equatable & SyncableEntity, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == PickerType {
var itemProvider: ItemProvider?
init() {
}
func foo() {
// Why doesn’t the implementation of refresh(:,completion:) we added get called here?
itemProvider?.refresh("dummy sender") {
}
}
}
class PopupPickerRow<T: Equatable & SyncableEntity, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == T {
var pickerController = GenericPickerViewController<T, ItemProvider>()
}
let pickerSectionProvider = PickerSectionProvider<ObservationType>()
let row = PopupPickerRow<ObservationType, PickerSectionProvider<ObservationType>>()
row.pickerController.itemProvider = pickerSectionProvider
row.pickerController.foo()
首先,当您想override
时method
中声明为protocol
的实现,并在protocol
{{1}中提供了一些默认实现时},它将始终调用extension
中实现的方法,并丢弃extension
子句要求。您可以在this问题和this中看到类似的问题。
因此,要使where
寻找protocol
来满足method
子句中的约束,您需要从where
除去method
签名并保持就像我上面所做的那样,它只在protocol
内部。
第二,您在定义extension
和PickerType
时错过了Equatable & SyncableEntity
是GenericPickerViewController
的要求,因此我也对此进行了更新。
答案 1 :(得分:2)
我在GenericPickerViewController
上添加了两个功能,一个用于通过PickerItemProvider
完全符合PickerType
的{{1}}对其进行设置,另一个使用{ {1}符合Equatable
的{1}}。这样,编译器便知道要调用哪个PickerItemProvider
。这是Playground代码:
PickerType