Reputation: 1879
I'm working on a music application that is able to play a playlist of songs, I have two data types representing a song in my project; "Track" which is of NSManagedObject for songs saved on the device by the user, and "JSONTrack" which represents songs decodable from a json web service. Users should be able to add both types to a an array of playlist. How do I achieve this with Swift, making an array for the different data types and work on that array: My current code handling one of the data types looks like this:
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
}
handling next and previous selection. I would like to do the same for two different types of songs which are represented by two different data types.
Upvotes: 0
Views: 533
Reputation: 4659
Using a protocol is probably the most common, but enum
also works well.
To elaborate on the enum
option:
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"
Upvotes: 1
Reputation: 17054
Multiple solutions to your problem here
You could make both JSONTrack
and Track
conforms to a protocol named TrackProtocol
for instance with common method names. Then you could manipulate your array of TrackProtocol
seamlessly.
Best solution
Create a TrackEnum
enum containing both.
enum TrackEnum {
case json(JSONTrack)
case coreData(Track)
}
Then your array is array of TrackEnum
and you extract every time which one it is.
You can do an array of Any
and check at runtime for the content type.
Worst solution.
Upvotes: 1
Reputation: 4011
Use a protocol that has the methods/properties necessary for next and previous actions. Have both of your track types implement the protocol. Have your array have the type of the protocol.
protocol Track {
title: String
albumTitle: String
// other method and properties
}
class JSONTrack: Track {
// implementation
}
class CoreDataTrack: Track {
// implementation
}
let tracks = [Track]()
Upvotes: 1