Swift中构建兼容多数据类型的播放列表数组并实现曲目切换
解决方案:用协议抽象统一两种Track类型
这个需求用Swift的协议抽象就能完美解决——两种Track本质上都是可播放的曲目,只是存储/来源不同,我们只需要提取它们的共同行为和属性,就能让播放列表同时兼容两者。
1. 定义通用可播放曲目协议
首先创建一个协议,把两种Track都具备的核心属性(比如曲目名、专辑名)抽象出来,如果后续有其他共同属性(比如时长、艺术家ID)也可以补充进去:
protocol PlayableTrack { var trackTitle: String { get } var albumTitle: String { get } // 可选:添加唯一标识符,避免同名同专辑歌曲的索引判断错误 // var uniqueTrackId: String { get } }
注意:如果
JSONTrack是引用类型(Class),可以给协议加上AnyObject限制(protocol PlayableTrack: AnyObject),和Track(NSManagedObject是引用类型)保持一致;如果是值类型(Struct),就不用加。
2. 让两种Track类型遵守协议
分别给Track和JSONTrack扩展,让它们自动遵守这个协议(因为它们本来就有对应的属性,不需要额外实现):
// 本地存储的Track(NSManagedObject) extension Track: PlayableTrack {} // 网络获取的JSONTrack extension JSONTrack: PlayableTrack {}
3. 修改播放列表与当前曲目类型
把原来的[Track]类型的播放列表,改成协议类型数组;同时当前播放的曲目也改成协议类型:
// 原来的 var playlistTracks = [Track]() var playlistTracks = [PlayableTrack]() // 原来的 var track: Track? var track: PlayableTrack?
4. 调整上下曲切换逻辑
只需要把原来代码中具体的Track类型替换成PlayableTrack,核心逻辑完全不用变——协议已经保证了所有元素都具备trackTitle和albumTitle属性:
@objc fileprivate func handlePrevTrack() { guard !playlistTracks.isEmpty, let currentTrack = track else { return } // 查找当前曲目在列表中的索引 let currentTrackIndex = playlistTracks.index { tr in currentTrack.trackTitle == tr.trackTitle && currentTrack.albumTitle == tr.albumTitle // 如果用了唯一标识符,改成下面的判断更准确: // currentTrack.uniqueTrackId == tr.uniqueTrackId } guard let index = currentTrackIndex else { return } let prevTrack: PlayableTrack if index == 0 { // 第一首的上一曲是最后一首 prevTrack = playlistTracks[playlistTracks.count - 1] } else { prevTrack = playlistTracks[index - 1] } self.track = prevTrack } @objc func handleNextTrack() { guard !playlistTracks.isEmpty, let currentTrack = track else { return } let currentTrackIndex = playlistTracks.index { tr in currentTrack.trackTitle == tr.trackTitle && currentTrack.albumTitle == tr.albumTitle // currentTrack.uniqueTrackId == tr.uniqueTrackId } guard let index = currentTrackIndex else { return } let nextTrack: PlayableTrack if index == playlistTracks.count - 1 { // 最后一首的下一曲是第一首 nextTrack = playlistTracks[0] } else { nextTrack = playlistTracks[index + 1] } self.track = nextTrack }
额外优化建议
用trackTitle+albumTitle判断曲目索引存在风险——如果有同名同专辑的不同歌曲,会导致索引判断错误。建议给协议添加一个唯一标识符属性(比如uniqueTrackId),用它来做索引判断,这样逻辑会更可靠。
内容的提问来源于stack exchange,提问作者Tobi Omotayo
相关产品推荐
相关产品推荐

