Hi all,
I'm running in to a really strange issue using filtering on a collection. It seems that its code execution within a closure is dependent on the return value of the closure.
I am writing a script to iterate through a directory of image files which are named frame-0.png
, frame-1.png
, up to frame-139.png
. I am trying to remove the .DS_Store
file, then sort the remaining strings the number in the file name rather than alphabetically.
To remove .DS_Store
. I added .drop { $0.hasPrefix(".") }
before the sort
operation. I noticed that the sort function was still operating on a collection containing .DS_Store
. I did a sanity check in a Playground and .drop { $0.hasPrefix(".") }
worked as expected on a smaller array.
Here is the function:
func getInputFilePaths(_ directory: String) -> [String]? {
guard let directoryURL = URL(string: directory),
let fileNames = try? FileManager.default.contentsOfDirectory(atPath: directory) else {
print("Failed to find contents for directory \(directory)")
return nil
}
return fileNames
.drop { $0.hasPrefix(".") }
.sorted { lhs, rhs in
guard let leftFileNumStr = lhs.split(separator: ".").first?.split(separator: "-").last,
let rightFileNumStr = rhs.split(separator: ".").first?.split(separator: "-").last,
let leftFileNum = Int(leftFileNumStr),
let rightFileNum = Int(rightFileNumStr) else {
print("invalid fileName: \"\(lhs)\" or \"\(rhs)\". Expected format: [name]-[integer].[extension]")
exit(1)
}
return leftFileNum < rightFileNum
}
.map { directoryURL.appendingPathComponent($0).absoluteString }
}
I rewrote the drop
closure in order to step through it, placing a breakpoint within an if block. For whatever reason, the breakpoint was not being hit, even though I knew .DS_Store
was in the array.
.drop {
if $0.hasPrefix(".") {
return true // breakpoint
}
return false
}
Then I tried flipping the return value at the bottom. In this case, the breakpoint WAS hit. I am not sure why a separate expression in the closure would affect the return value of hasPrefix(".")
.drop {
if $0.hasPrefix(".") {
return true // breakpoint
}
return true
}
I am perplexed by this, and am able to reproduce it consistently. Here is a GitHub repo with the entire code. I'm not sure what's causing the issue. I could find alternate ways to remove the unwanted string, but the behavior I am experiencing seems worth raising. It smells like something deeper than user error, so I decided to bring it to the Swift forums rather than Apple Developer forums.