In my SwiftUI app, I have a UpNextManager view model and a service class called UpNextService which contains many methods to read up next items from disk, write them to disk and much more. The service class is then injected into the view model. However, the issue is alot of the service class methods require isShuffled state from the view model.
Would it be better to pass the state as a parameter to the functions in the service (i.e. which means having the same isShuffled parameter in over 15 functions) or make the service class observable (i.e. make it as another view model that views can watch for changes) instead and hold the isShuffled state inside it?
I have 3 fundamnetal classes in my app: UpNextViewModel, UpNextService and AudioPlaybackService.
UpNextViewModel directly communicates with the UI to handle shuffle, repeat and showing the next 100 up next items in the view.
UpNextService handles reading and writing up next items to disk, retrieving the exact item at a certain index, holding the current playing item for reference.
AudioPlaybackService handles playback stuff like forward and rewind and needs access to the current playing item, repeat status which needs to come from upnextservice
struct UpNextItem {
var id = UUID()
var audioFileId: UUID
}
enum RepeatStatus: CaseIterable {
case none
case oneTime
case loop
}
// Directly works with UpNextView when user taps on button to switch on shuffle
@Observable
class UpNextViewModel {
var repeatStatus: RepeatStatus = .none
var isShuffled: Bool = false
let upNextService: UpNextService
init(upNextService: UpNextService) {
self.upNextService = upNextService
}
}
class UpNextService {
var currentPlayingItem: UpNextItem? = nil
var currentPlayingIndex = 0
func writeItems() {
// Need isShuffled state in the logic
let url = shuffled
? FileManager.shuffledUpNextQueueURL
: FileManager.originalUpNextQueueURL
let (data, _) = try await URLSession.shared.data(from: url)
// More writing logic
}
func readItems() -> [UpNextItem] {
// Need isShuffled state in the logic
let url = shuffled
? FileManager.shuffledUpNextQueueURL
: FileManager.originalUpNextQueueURL
let (data, _) = try await URLSession.shared.data(from: url)
// More reading logic
}
func removeItem(at index: Int) {
// Need isShuffled state in the logic
let url = shuffled
? FileManager.shuffledUpNextQueueURL
: FileManager.originalUpNextQueueURL
let (data, _) = try await URLSession.shared.data(from: url)
// Removing item logic
}
}
class AudioPlaybackService {
let upnextService: UpNextService
init(upNextService: UpNextService) {
self.upnextService = upNextService
}
func forward() {
switch upnextService.repeatStatus {
case .none:
// Logic to forward to next item
case .oneTime:
// Logic to forward to same item again
// and disable repeat status to none
case .loop:
// Logic to forward to same item
}
}
func rewind() {
// Get previous item
let previousItem = upnextService
.readItems()[upnextService.currentPlayingIndex - 1]
// More business logic
}
}
-
hard to say without the full details, but assuming the shuffled state is shared across views, then whats the downside of just having service.IsShuffled, service.Shuffle, service.UnShuffle etcEwan– Ewan03/11/2025 13:02:31Commented Mar 11 at 13:02
1 Answer 1
A third option would be to stop needing state to be externalized. In the OOP paradigm you move behavior to where the data lives and encapsulate the data. Then rather then ask for state you tell whatever has the state to do what you want done. Since it already knows its state it knows what to do.
Done this way you don't need to ask, pass to 15 functions, or observe. You just tell the shuffled/not shuffled thing what you want done and it figures out what to do.
class UpNextServiceShuffled {
func writeItems() {
// Don't need isShuffled state in the logic
let url = FileManager.shuffledUpNextQueueURL
...
}
class UpNextServiceOriginal {
func writeItems() {
// Don't need isShuffled state in the logic
let url = FileManager.originalUpNextQueueURL
...
}
-
Could you give some example code/pseudocode? It’s very hard to visualise from pure wordsUser95797654974– User9579765497403/13/2025 05:11:54Commented Mar 13 at 5:11
-
@User95797654974 right now the behavior I'd be moving is a comment:
//Need isShuffled state in the logic
If you want my code to look better than that I need you to detail your code.candied_orange– candied_orange03/13/2025 09:38:54Commented Mar 13 at 9:38 -
Here are the full details: I have 3 fundamnetal classes in my app: UpNextViewModel, UpNextService and AudioPlaybackService. UpNextViewModel directly communicates with the UI to handle shuffle, repeat and showing the next 100 up next items in the view. UpNextService handles reading and writing up next items to disk, retrieving the exact item at a certain index, holding the current playing item for reference. AudioPlaybackService handles playback stuff like forward and rewind and needs access to the current playing item, repeat status which needs to come from upnextserviceUser95797654974– User9579765497403/15/2025 08:18:39Commented Mar 15 at 8:18
-
@User95797654974 I was hoping you’d edit code into your question that I’d be able to move.candied_orange– candied_orange03/15/2025 12:35:58Commented Mar 15 at 12:35
-
Ive added more details on where the service class for up next is usedUser95797654974– User9579765497403/16/2025 10:10:12Commented Mar 16 at 10:10
Explore related questions
See similar questions with these tags.