0

I'm creating a music player. It plays tracks from device memory (from Documents folder). I ran into a problem that when there are many tracks (200 or more), then at the moment of loading the list of tracks, my interface freezes. I searched for the source of the problem for a long time, tried different options and I found it - this is the function createPlayerQueue in which I create the playerQueue.
I want to understand: is this really taking so much resources from the device or is my code not very good? How can I solve this problem?

func createPlayerQueue(from content: [URL]) -> [AVPlayerItem] {
        var playerQueue: [AVPlayerItem] = []
        let items = content.map { AVURLAsset(url: $0) }.map { AVPlayerItem(asset: $0) } //at this point the interface freezes
        playerQueue = items
        return playerQueue
    }

I use function result to create my models:

private var playerQueue: [AVPlayerItem] = []

func setupTrackModels(content: [URL]) -> [TrackModelProtocol] {
        playerQueue = audioPlayer.createPlayerQueue(from: content)
        var tracks: [TrackModelProtocol] = []
        
        for index in 0..<playerQueue.count {
            
            var artwork: UIImage?
            
            let playerItem = playerQueue[index]
            let metadataList = playerItem.asset.metadata
            
            for item in metadataList {
                guard let key = item.commonKey?.rawValue, let value = item.value else {
                    continue
                }
                
                switch key {
                case "artwork" where value is Data:
                    artwork = UIImage(data: value as! Data)
                default:
                    continue
                }
            }
            
            let track = TrackFromDeviceMemory(
                fileName: content[index].lastPathComponent,
                duration: playerQueue[index].asset.duration.seconds,
                artwork: artwork,
                url: content[index].absoluteURL)
            
            tracks.append(track)
        }
        
        return tracks
    }

I call this function in the viewWillAppear function so that I can get the actual list of files every time I return to this view.

1 Answers1

1

Stumbled upon a similar issue a few days ago and figured out that AVPlayerItem instantiation is resource-heavy, so it's a good idea to dispatch it to the custom queue. This page covers the topic in great details.

Also, a little nitpick - you can shorten your createPlayerQueue method to this, no need to assign items to playerQueue, and since there's only one line of code, even return can be omitted:

func createPlayerQueue(from content: [URL]) -> [AVPlayerItem] {
    content.map { AVURLAsset(url: $0) }.map { AVPlayerItem(asset: $0) }
}
Artem Garmash
  • 154
  • 10