简体   繁体   English

如何从 macOS 应用程序中的文件系统读取图像

[英]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:用户对 select 图像的代码是:

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.我比较了设置一个断点pathName == selectedPath并且它们是相等的。

However, doing然而,做

NSImage(contentsOfFile: pathName!)

is nil .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 ?也许还有 NSUserDefaults 作为images.data

I appreciate the help.我很感激帮助。

Thanks for the link in the comments by @matt, I implemented the answer.感谢@matt 评论中的链接,我实现了答案。 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.点击 App -> Target -> Signin & Capabilities -> App Sandbox 并更改文件访问类型的“权限和访问”。 Xcode will ask you if you want to create an entitlements file. Xcode 会询问您是否要创建授权文件。 Accept it.接受。 Revert the change you did if you do not need it.如果您不需要它,请还原您所做的更改。 Now you will have the file <AppName>/<AppName>Release.entitlements .现在您将拥有文件<AppName>/<AppName>Release.entitlements Add the entitlement that enables the user of app-scoped bookmarks and URLs ( Apple Docs ).添加允许用户使用应用范围内的书签和 URL ( 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).创建一个Codable结构,用于保存书签数据和图像名称(或您可能拥有并需要保存的任何Codable数据)。
struct CodableImage: Codable {
    let bookmarkData: Data
    let name: String
}
  1. Bookmark the URL:收藏 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 :首先从CodableImage获取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:最后,从解析的 url 创建映像:

let image = NSImage(contentsOf: url)

Credit to URL Bookmarks: yes and no for the stale data renewal logic. 归功于 URL 书签:陈旧数据更新逻辑是和否

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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