While retrieving metadata from media files, I've run into a memory issue I cannot figure out.
I want to retrieve metadata for media files either stored in the local app storage or in the iTunes area. For this I use AVAsset. While looping through these files I can see the memory consumption rising constantly. And not just a little. It is significant and end up stalling the app when I enumerate my iTunes library on the phone.
The problem seems to be accessing the metadata property on the AVAsset class. I've narrowed in down to one line of code: 'let meta = ***.metadata'. Having that line of code (without any references) makes the app consume memory. I've included an example of my code structure.
func processFiles(_ files:Array)
{
var lastalbum : String = ""
var i : Int = 0
for file in files
{
i += 1
view.setProgressPosition(CGFloat(i)/CGFloat(files.count))
lastalbum = updateFile(file.url,lastalbum,
{ (album,title,artist,composer) in
view.setProgressNote(album,title,artist+" / "+composer)
})
}
}
func updateFile(_ url:URL,_ lastalbum:String,iPod:Bool=false,
_ progress:(String,String,String,String) -> Void) -> String
{
let *** = AVAsset(url:url)
let meta = ***.metadata
for item in meta
{
// Examine metadata
}
// Use metadata
// Callback with status
}
It seems that memory allocated in the updateFile method, is kept, even when the function is ended. However, once the processFile function completes and the app returns to a normal state, all memory is released again.
So in conclusion, this is not a real leak, but still a significant problem. Any good ideas as to what goes wrong? Is there any way I can force the memory management to run a cleanup?
It seems the solution lies in using 'autoreleasepool'. If I wrap the code in updateFile with a autoreleasepool block, the memory buildup is reduced to a minimum, which is within what I expect is needed during the processing. In a small test I reduced the buildup from 243 MB to less than 7 MB, so I considder this solved.