Я работаю над музыкальным приложением, которое может воспроизводить список воспроизведения песен, у меня есть два типа данных, представляющих песню в моем проекте; «Track» - это NSManagedObject для песен, сохраненных на устройстве пользователем, и «JSONTrack», представляющий песни, декодируемые из веб-службы json. Пользователи должны иметь возможность добавлять оба типа в массив плейлистов. Как мне добиться этого с помощью Swift, создав массив для разных типов данных и работая с этим массивом: Мой текущий код, обрабатывающий один из типов данных, выглядит так:
var playlistTracks = [Track]()
@objc fileprivate func handlePrevTrack() {
if playlistTracks.isEmpty {
return
}
let currentTrackIndex = playlistTracks.index { (tr) -> Bool in
return self.track?.trackTitle == tr.trackTitle && self.track?.albumTitle == tr.albumTitle
}
guard let index = currentTrackIndex else { return }
let prevTrack: Track
if index == 0 {
let count = playlistTracks.count
prevTrack = playlistTracks[count - 1]
} else {
prevTrack = playlistTracks[index - 1]
}
self.track = prevTrack
}
@objc func handleNextTrack() {
if playlistTracks.count == 0 {
return
}
let currentTrackIndex = playlistTracks.index { (tr) -> Bool in
return self.track?.trackTitle == tr.trackTitle && self.track?.albumTitle == tr.albumTitle
}
guard let index = currentTrackIndex else { return }
let nextTrack: Track
if index == playlistTracks.count - 1 {
nextTrack = playlistTracks[0]
} else {
nextTrack = playlistTracks[index + 1]
}
self.track = nextTrack
}
обработка следующего и предыдущего выбора. Я хотел бы сделать то же самое для двух разных типов песен, которые представлены двумя разными типами данных.





Используйте протокол, который имеет методы / свойства, необходимые для следующих и предыдущих действий. Попросите оба ваших типа треков реализовать протокол. Ваш массив должен иметь тип протокола.
protocol Track {
title: String
albumTitle: String
// other method and properties
}
class JSONTrack: Track {
// implementation
}
class CoreDataTrack: Track {
// implementation
}
let tracks = [Track]()
но мой CoreDataTrack имеет NSManagedObject, Xcode обычно не хочет, чтобы кто-то редактировал эти автоматически сгенерированные файлы, могу ли я все же привести его в соответствие с протоколом?
Хорошо, я нашел способ вручную сгенерировать классы базовой модели данных, чтобы я мог настроить их, чтобы они приняли протокол. Спасибо
Множественные решения вашей проблемы здесь
Вы можете сделать так, чтобы и JSONTrack, и Track соответствовали протоколу с именем TrackProtocol, например, с общими именами методов. Тогда вы сможете легко манипулировать своим массивом TrackProtocol.
Лучшее решение
Создайте перечисление TrackEnum, содержащее оба.
enum TrackEnum {
case json(JSONTrack)
case coreData(Track)
}
Тогда ваш массив - это массив TrackEnum, и вы каждый раз извлекаете, какой именно.
Вы можете создать массив Any и проверить во время выполнения тип содержимого.
Худшее решение.
Использование протокола, вероятно, является наиболее распространенным, но enum также работает хорошо.
Чтобы уточнить вариант enum:
class JSONTrack: NSObject {}
class OtherTrack: NSObject {}
enum Track {
case jsonTrack(JSONTrack)
case otherTrack(OtherTrack)
// enum can be handy if you want to do type checking
// and e.g. present specific data for that type
var label: String {
switch self {
case .jsonTrack:
return "Json track"
case .otherTrack:
return "Other track"
}
}
}
let jsonTrack = JSONTrack()
let otherTrack = OtherTrack()
let tracks: [Track] = [Track.jsonTrack(jsonTrack), Track.otherTrack(otherTrack)]
let labelOfTrack1 = tracks.first!.label
print(labelOfTrack1)
// prints "Json track"
Я собирался предложить либо этот, либо даже
enum, где он может быть того или иного типа. Я думаю, что предпочитаю этот протокол: D