I'm just trying to display an image that is stored in the local filesystem, but the more I dig into this the more confused I get.
So previously I used this code (it's simplified):
func findImage(name: String) -> UIImage? {
do {
let url = try FileManager.default.url(for: .applicationSupportDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: false)
.appendingPathComponent("MyFolder")
.appendingPathComponent("\(name).png")
guard let image = UIImage(contentsOfFile: url.path) else {
return nil
}
return image
} catch {
print(error.localizedDescription)
}
return nil
}
Notice I create the URL with just .appendingPathComponent()
and turning URL to path
via url.path
.
It works! So what's the question?
-
In Improving performance and stability when accessing the file system I've read that you better use the new
appendingPathComponent(_:isDirectory:)
, that's good, will do. -
Also
url.path
is deprecated in iOS18. Should I useurl.path(percentEncoded:)
instead? What should be the value ofpercentEncoded
when accessing the local filesystem?
In this adjacent thread I've read:
Don't use UIImage(contentsOfFile:) either, because it's a path-based API. There's no URL-based equivalent, which is an Apple clue that should be doing something else.
Is this true? Then how should I store and load my images?
Just FYI, I create images like this:
private func generateThumbnail(name: String) {
guard let drawingWidth = canvasGeo?.size.width,
let drawingHeight = canvasGeo?.size.height else { return }
let thumbnailRect = CGRect(x: 0, y: 0, width: drawingWidth, height: drawingHeight)
Task {
UITraitCollection(userInterfaceStyle: .light).performAsCurrent {
let image = self.canvasView.drawing.image(from: thumbnailRect, scale: UIScreen.main.scale)
guard let data = image.pngData() else { return } // -- HERE
do {
try FileManager.default.createDirectory(at: try FileManager.default.url(for: .applicationSupportDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true)
.appendingPathComponent("MyFolder"),
withIntermediateDirectories: true,
attributes: nil)
let filename = "\(name).png"
let url = try FileManager.default.url(for: .applicationSupportDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true)
.appendingPathComponent("MyFolder")
.appendingPathComponent(filename)
try data.write(to: url, options: .atomic) // -- and HERE
} catch {
print(error.localizedDescription)
}
}
}
}
My usecase — just save the user's PencilKit Canvas as an image and display it back to him on a different View. I'm on SwiftUI and iOS 16+.
Would be happy to learn the correct way, thanks!
Regarding .appendingPathComponent(…)
, there is now appending(path:directoryHint:)
, which is even more explicit.
Note that in this situation the cost of the extra stat
required to confirm whether a URL is a directory or a file will be completely drowned out by the cost of reading and decompressing the image.
Regarding, url.path
, my preferred option is to simple ignore the deprecation and continue using that property O-: However, the answer to your direct question is that you should pass in false
. Consider:
import Foundation
func main() {
let u = URL(fileURLWithPath: "/Users/quinn/naïve.txt")
print(u.path)
print(u.path())
print(u.path(percentEncoded: false))
print(u.path(percentEncoded: true))
}
main()
which prints:
/Users/quinn/naïve.txt
/Users/quinn/nai%CC%88ve.txt
/Users/quinn/naïve.txt
/Users/quinn/nai%CC%88ve.txt
Is this true? Then how should I store and load my images?
It’s hard to say for sure. There are two common reasons for not replacing paths with file URLs:
-
That API is deprecated in some way, perhaps formally or perhaps informally.
-
We’ve just not got around to it!
It’s hard to tell these apart. For non-UI framework I have enough experience that I can offer up an opinion. For UI frameworks like this I’m on less solid ground. If you really want an answer, I recommend that you start a new thread in the UI Frameworks > UIKit topic area.
I will, however, point out that UIImage(contentsOfFile:)
is most definitely a convenience method. There are lots of APIs for wrangling images, with lots of very cool features.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"