【问题标题】:How to provide default implementation of protocol's methods for generic class and its subclasses?如何为泛型类及其子类提供协议方法的默认实现?
【发布时间】:2020-11-16 15:55:21
【问题描述】:

我目前正在学习 Swift 的泛型,但在将协议与泛型类一起使用时遇到了问题。我需要创建 4 个继承自 AWMediaItemWrapper 泛型类的包装类。

public class MPMediaItemWrapper<M: MPMediaEntity> {
    internal let value: M
    init(_ value: M) {
        self.value = value
    }
}

MPMediaEntity 是来自MediaPlayer 框架的抽象类。从它继承的三个子类是一样的:

public class MPTrack: MPMediaItemWrapper<MPMediaItem> {}
public class MPAlbum: MPMediaItemWrapper<MPMediaItem> {}
public class MPArtist: MPMediaItemWrapper<MPMediaItem> {}

除了第四个:

public class MPPlaylist: MPMediaItemWrapper<MPMediaPlaylist> {}

我还有一个协议AWMediaItem,它定义了一些属性和方法

public protocol AWMediaItem: class {
    /// Unique identifier of the item.
    var uid: String { get }
    
    /// Name used to identify the item, for example album title or artist name.
    var name: String { get }

    /// Source of the object.
    var source: AWMediaSource { get }

    ...
}

现在我想做的是为MPMediaItemWrapper 子类创建一个默认的AWMediaItem 实现,其中M 类是MPMediaEntityMPMediaItemMPMediaPlaylist 都是它的子类)

我已经写了这段代码

public extension AWMediaItem where Self: MPMediaItemWrapper<MPMediaEntity> {
    var source: AWMediaSource {
        return .iTunes
    }
    
    var uid: String {
        return String(value.persistentID)
    }
}

它没有给我错误,但编译器说所有三个子类都缺少协议要求。

类型“MPArtist”不符合协议“AWMediaItem”

类型“MPAlbum”不符合协议“AWMediaItem”

类型“MPTrack”不符合协议“AWMediaItem”

类型“MPPlaylist”不符合协议“AWMediaItem”

如果我将协议扩展更改为

public extension AWMediaItem where Self: MPMediaItemWrapper<MPMediaItem>

满足MPTrackMPAlbumMPArtist 的协议要求,但不满足MPPlaylist 的协议要求。有什么方法可以编写扩展使其适用于所有这些子类?

【问题讨论】:

  • 复制粘贴....没有编译器错误。 Xcode 12.1 / iOS 14.1。你没有忘记什么吗?
  • 您需要实际尝试使 4 个子类符合协议才能查看编译器错误。
  • 没错,@flanker

标签: ios swift generics swift-protocols


【解决方案1】:

我认为您的问题的根源是您假设继承自用于实例化泛型的特定类型,但事实并非如此。

MPTrack.self is MPMediaItemWrapper&lt;MPMediaEntity&gt;.Type 总是会失败

MPTrack.self is MPMediaItemWrapper&lt;MPMediaItem&gt;.Type 永远为真

尽管MPMediaItemNPMedidiaEntity 的子类,MPMediaItemWrapper&lt;MPMediaItem&gt; 不是MPMediaItemWrapper&lt;MPMediaEntity&gt; 的子类。简单来说,两者是完全不同的类,兄弟姐妹多于 parent:child。

因此,您不会从默认实现中获得您在协议中所期望的行为,因为

public extension AWMediaItem where Self: MPMediaItemWrapper&lt;MPMediaEntity&gt;

不会适用于您的任何课程,因为它们都不符合 where 子句。因此他们没有得到默认实现并给出一致性错误。

但是其中三个类是作为MPMediaItemWrapper&lt;MPMediaItem&gt; 的子类创建的,所以当您将协议扩展更改为

public extension AWMediaItem where Self: MPMediaItemWrapper&lt;MPMediaItem&gt;

他们现在确实符合,获得默认实现,并且不会出错。但是,您的播放列表类仍然不符合要求,因为它继承自 MPMediaItemWrapper&lt;MPMediaPlaylist&gt;

简单的解决方案是拥有两个扩展,都具有相同的默认实现,一个用于

public extension AWMediaItem where Self: MPMediaItemWrapper&lt;MPMediaItem&gt;

一个用于

public extension AWMediaItem where Self: MPMediaItemWrapper&lt; MPMediaPlaylist&gt;

当我想出更好的方法来做到这一点时,我确信有一个,我会更新答案!

【讨论】:

  • 感谢您如此清晰地解释这一点!我以错误的方式考虑继承
猜你喜欢
  • 1970-01-01
  • 2010-11-09
  • 2011-05-18
  • 2015-08-21
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 2016-08-19
  • 1970-01-01
相关资源
最近更新 更多