协议只能用作通用约束

Protocol can only be used as a generic constraint

我有一个 MapViewController 用于在地图上显示注释。它包含一个 MapPresentable 类型的对象。

protocol MapPresentable {
    associatedtype AnnotationElement: MKAnnotation
    var annotations: [AnnotationElement] { get }
}

class MapViewController<M: MapPresentable>: UIViewController {
    var mapPresentable: M!
}

如果mapPresentable符合RoutePresentable协议,MapViewController也可以在地图上呈现路线。

protocol RoutePresentable: MapPresentable {
    var getRouteLocations: [CLLocation] { get }
}

但是检查里面的时候MapViewController

if let routePresentable = mapPresentable as? RoutePresentable {
    showRoute(routePresentable.getRouteLocations)
}

我收到这个错误:

Protocol 'RoutePresentable' can only be used as a generic constraint because it has Self or associated type requirements

已更新

对不起,我错了。但是无法使用 associated type.

来转换协议

希望这会有所帮助。

据我所知,routePresentable.getRouteLocations 与协议 MapPresentable 无关。

所以你可以把RoutePresentable分成两个协议:

protocol MapPresentable {
    associatedtype AnnotationElement: MKAnnotation
    var annotations: [AnnotationElement] { get }
}

class MapViewController<M: MapPresentable>: UIViewController {
    var mapPresentable: M!

}

protocol RoutePresentable: MapPresentable, CanGetRouteLocations {}

protocol CanGetRouteLocations {
    var getRouteLocations: [CLLocation] { get }
}


if let routePresentable = mapPresentable as? CanGetRouteLocations {
    showRoute(routePresentable.getRouteLocations)
}

原创

因为routePresentable.annotations的类型未提供,

您可以删除 associatedtype AnnotationElement: MKAnnotation

或者改为用户通用结构:

struct MapPresentable<AnnotationElement: MKAnnotation> {
    var annotations: [AnnotationElement] = []
}

struct RoutePresentable<AnnotationElement: MKAnnotation> {
    var mapPresentable: MapPresentable<AnnotationElement>
    var getRouteLocations: [CLLocation] = []
}

class MapViewController<AnnotationElement: MKAnnotation>: UIViewController {

    var mapPresentable: MapPresentable<AnnotationElement>!

}

if let routePresentable = mapPresentable as? RoutePresentable<MKAnnotation> {
    showRoute(routePresentable.getRouteLocations)
}