简体   繁体   中英

How to read image from file system within macOS app

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.

  1. Add entitlements to app. Tap on App -> Target -> Signin & Capabilities -> App Sandbox and change the "Permission & Access" of an of the File Access Types. Xcode will ask you if you want to create an entitlements file. Accept it. Revert the change you did if you do not need it. Now you will have the file <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>
  1. Create a struct that is 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
}
  1. Bookmark the URL:
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)
}
  1. Retrieve the data

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM