May app opens a dialog, allows selecting an image and shows it to the user. The code for the user to select the image is:
let myFiledialog = NSOpenPanel()
myFiledialog.prompt = "Upload image"
myFiledialog.canChooseDirectories = false
myFiledialog.canChooseFiles = true
myFiledialog.allowedFileTypes = ["png", "jpg", "jpeg"]
myFiledialog.allowsMultipleSelection = false
myFiledialog.begin { [weak self] result -> Void in
guard
result.rawValue == NSApplication.ModalResponse.OK.rawValue,
let selectedPath = myFiledialog.url?.path
else {
return
}
guard let image = NSImage(contentsOfFile: selectedPath) else {
return
}
someImageView.image = image
UserDefaults.standard.set(selectedPath, forKey: "imagePath")
}
I display the image correctly. The idea is that the user can close the app, open it and get to see the image.
I am getting the image name:
let pathName = UserDefaults.standard.string(forKey: "imagePath")
I compared setting a breakpoint that pathName == selectedPath
and they are equal.
However, doing
NSImage(contentsOfFile: pathName!)
is nil
.
Does this have to do with the permissions I need to acquire to read data in the file system? Should I save the user images somewhere else where I could access them? Maybe also the NSUserDefaults as images.data
?
I appreciate the help.
Thanks for the link in the comments by @matt, I implemented the answer. Leaving it here in case helpful with anyone.
<AppName>/<AppName>Release.entitlements
. Add the entitlement that enables the user of app-scoped bookmarks and URLs ( Apple Docs ). This is how may file looks like:<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
</dict>
</plist>
Codable
that saves the bookmark data and the image name (or whichever Codable
data you may have and need to save).struct CodableImage: Codable {
let bookmarkData: Data
let name: String
}
do {
let data = try url.bookmarkData()
let codableImage = CodableImage(bookmarkData: data, name: "Awesome image")
UserDefaults.standard.set(try? JSONEncoder().encode(codableImage), forKey: "kImageKey")
} catch {
print(error)
}
First get the CodableImage
from UserDefaults
:
guard
let encodedImageData = UserDefaults.standard.value(forKey: "kImageKey") as? Data,
let codableImage = try? JSONDecoder().decode(CodableImage.self, from: encodedImageData)
else {
// Data could not be read or decoded or both :(
return
}
The resolve the bookmark data and renew the bookmark if the resolved one is stale:
var isBookmarkStale = false
guard let url = try? URL(resolvingBookmarkData: codableImage.bookmarkData, bookmarkDataIsStale: &isBookmarkStale) else {
return nil
}
if isBookmarkStale {
print("Bookmark is stale. renewing.")
// If bookmark data is stale, all occurences have to be updated.
let _ = try? url.bookmarkData()
}
Lastly, create the image from the resolved url:
let image = NSImage(contentsOf: url)
Credit to URL Bookmarks: yes and no for the stale data renewal logic.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.