1

I'm trying to edit the queue of my music player using the applicationQueuePlayer and the perform method (details here). However, whenever I apply any array function (map, filter etc.), it takes many seconds to complete, leading to (I think) data races and crashes when the user, for example, removes two tracks immediately after each other.

    var musicPlayerController = MPMusicPlayerController.applicationQueuePlayer

    self.musicPlayerController.perform { (currentQueue) in
        let items = currentQueue.items
        let itemsToRemove = items.filter { $0.artist == "Some artist" } // this takes multiple seconds
        if let item = itemsToRemove.first {
            currentQueue.remove(item)
        }
    } completionHandler: { (newQueue, error) in
        if let e = error {
            print(e)
        } else {
            tracks = items.map { Track(item: $0) } // this takes multiple seconds
        }
    }

The issue is arising as I'm going through an MPMediaItem array. I don't think this is an issue with the MPMediaItem class though, as I'm able to complete a map of [MPMediaItem] in other places in the app e.g. when getting items from a playlist (a similar sized array to the queue items).

The issue happens solely when the MPMediaItems are taken from the MPMusicPlayerControllerMutableQueue and MPMusicPlayerControllerQueue

Is this just a bug with MusicKit API?

Jack Vanderpump
  • 216
  • 2
  • 16
  • I've not the answer but filtering the whole items to remove the first one is not optimize. Instead: `if let item = items.first(where: { $0.artist = "Some artist" } { currentQueue.remove(item) }`. What crash do you have? Which one is causing it? `tracks`? – Larme Jun 05 '21 at 13:35
  • Yeah it’s a simplified bit of code - but I’ve left a bit in, so should remove the if let check and go straight to the remove method. I’m getting an Exc_bad_access crash – Jack Vanderpump Jun 05 '21 at 15:05
  • Both the filter and the map methods cause the crash – and any other array function that takes ages to cycle through – Jack Vanderpump Jun 05 '21 at 17:30
  • This seems really strange to me. How big is `items`? If it's huge, does something like `let items = currentQueue.items.prefix(100)` help? Clearly that's not what you want to do in production, but it could help us diagnose. You could also try doing `let items = currentQueue.items.lazy`. This will probably cause compiler errors due to mis-matched types, but avoid wrapping things in `Array` and instead actually store a `LazySequence>>` (probably can spell this just `LazySequence`) and you _might_ see better performance. – deaton.dg Jun 12 '21 at 18:36
  • Also make sure you're using the [`enumerateValues(forProperties:using:)`](https://developer.apple.com/documentation/mediaplayer/mpmediaentity/1620122-enumeratevalues) in your `Track` initializer if you are using multiple media properties. – deaton.dg Jun 12 '21 at 18:39
  • Thanks Deaton for your suggestions, and while the issue is more pronounced on bigger arrays, iteration is definitely slower item for item when it comes from the queue. I've written a small app to demonstrate the issue, which can be seen here: https://developer.apple.com/forums/thread/682064?login=true&page=1 – Jack Vanderpump Jun 15 '21 at 09:43

0 Answers0