The following task is given:
I wrote this tiny command line program:
import ArgumentParser
import AppKit
import Foundation
struct CheckImages: ParsableCommand {
@Option(help: "The images root directory")
var path: String
func run() throws {
let directories = try FileManager.default.contentsOfDirectory(atPath: path)
for directory in directories {
if directory == ".DS_Store" {
continue
}
let prefix = self.path + "\(directory)/PREFIX_\(directory)"
let imageName = prefix + ".jpg"
let image = NSImage(contentsOfFile: imageName)
if image == nil {
print("PROBLEM \(imageName)")
}
}
}
}
CheckImages.main()
Each image is around 20MB in size. Altogether I have ~150.000 images to check.
Unfortunately XCode terminates the program with Program ended with exit code: 9
. Digging deeper (with Instruments) it turns out that this little help application consumes all my memory in NSImage.init()
. As NSImage
is a mature object, I doubt that there is any problem with it. Thus, my question is, can anybody explain this behaviour to me?
My environment:
Answering my own question, I need an autorelease pool here. As I was never programming in Objective-C I was not aware of such things as autorelease pools. As NSImage
is 'just' a wrapper around the ObjC-NSImage object it needs an autorelease pool to manage the deallocation. We are in 2020 and we have to manager such things in this way?
In this post I found the answer to the above problem: Is it necessary to use autoreleasepool in a Swift program?
Another nice post can be found here: https://swiftrocks.com/autoreleasepool-in-2019-swift.html
So, the above code has to look like this:
import ArgumentParser
import AppKit
import Foundation
struct CheckImages: ParsableCommand {
@Option(help: "The images root directory")
var path: String
func run() throws {
let directories = try FileManager.default.contentsOfDirectory(atPath: path)
for directory in directories {
if directory == ".DS_Store" {
continue
}
autoreleasepool {
let prefix = self.path + "\(directory)/PREFIX_\(directory)"
let imageName = prefix + ".jpg"
let image = NSImage(contentsOfFile: imageName)
if image == nil {
print("PROBLEM \(imageName)")
}
}
}
}
}
CheckImages.main()