I'm having difficult saving and, more importantly, retrieving URL bookmark data.
I'm following the docs here https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/AccessingFilesandDirectories/AccessingFilesandDirectories.html#//apple_ref/doc/uid/TP40010672-CH3-SW10
The resulting file written to my app's sandbox is a "MacOS Alias file". which is what I expect as per the docs :
If you write the persistent bookmark data to disk using the writeBookmarkData:toURL:options:error: method of NSURL, what the system creates on disk is an alias file.
The result when performing my get call is always Error Domain=NSCocoaErrorDomain Code=259 "The file couldn’t be opened because it isn’t in the correct format." which leads me to believe I'm not initializing my Data object correctly before calling resolvingBookmarkData.
I'm also lead to believe my Data initialization is the problem as I use the same code but instead of writing data to disk with try URL.writeBookmarkData(bookmarkData, to: fileURL) I store the Data in UserDefaults. Retriving that data from UserDefaults succeeds.
Any help is appreciated. Thanks in advance.
private func save(fileURL: URL, completion: ((URL?) -> ())?) {
do {
// create bookmark data
let bookmarkData = try fileURL.bookmarkData(
options: .suitableForBookmarkFile, // create fails without this
includingResourceValuesForKeys: nil,
relativeTo: nil
)
// save bookmark data
try URL.writeBookmarkData(bookmarkData, to: fileURL)
print("write bookmark data to: \(fileURL)")
completion?(nil)
} catch {
print(error.localizedDescription)
}
}
private func get(completion: ((URL?) -> ())?) {
do {
var bookmarkDataIsStale = false
// get bookmark data
let fileUrl = listFile()
// output:
// read Data contents of: file:///Users/me/Library/Developer/CoreSimulator/Devices/E3302B79-7520-4731-BC42-14D848B7DABD/data/Containers/Data/Application/66E23F7C-D345-4E4F-9F93-6825721731CE/Documents/Recordings/recording.wav
print("read Data contents of: \(fileUrl)")
// no luck; results in 'Error Domain=NSCocoaErrorDomain Code=259 "The file couldn’t be opened because it isn’t in the correct format."'
let bookmarkData = try Data(contentsOf: fileUrl)
// no luck; results in 'Error Domain=NSCocoaErrorDomain Code=259 "The file couldn’t be opened because it isn’t in the correct format."'
// let bookmarkData = try Data(contentsOf: fileUrl, options: .alwaysMapped)
// no luck; results in 'Error Domain=NSCocoaErrorDomain Code=259 "The file couldn’t be opened because it isn’t in the correct format."'
// let bookmarkData = FileManager.default.contents(atPath: fileUrl.path)!
// get resolved url with bookmark data
// debugging
// output:
// resourceValues: URLResourceValues(_values: [__C.NSURLResourceKey(_rawValue: _NSURLPathKey): /Users/pouriaalmassi/Library/Developer/CoreSimulator/Devices/E3302B79-7520-4731-BC42-14D848B7DABD/data/Containers/Data/Application/66E23F7C-D345-4E4F-9F93-6825721731CE/Documents/Recordings/recording.wav, __C.NSURLResourceKey(_rawValue: NSURLCanonicalPathKey): /Users/pouriaalmassi/Library/Developer/CoreSimulator/Devices/E3302B79-7520-4731-BC42-14D848B7DABD/data/Containers/Data/Application/66E23F7C-D345-4E4F-9F93-6825721731CE/Documents/Recordings/recording.wav], _keys: Set([__C.NSURLResourceKey(_rawValue: NSURLCanonicalPathKey), __C.NSURLResourceKey(_rawValue: _NSURLPathKey)]))
let resourceValues = try! fileUrl.resourceValues(
forKeys: [
URLResourceKey.pathKey,
URLResourceKey.canonicalPathKey
]
)
print("resourceValues: \(resourceValues)")
// on options
// used `.withoutUI` as it follows Apple's docs. Linked below.
let resolvedUrl = try URL(
resolvingBookmarkData: bookmarkData,
options: [.withoutUI, .withoutImplicitStartAccessing],
relativeTo: nil,
bookmarkDataIsStale: &bookmarkDataIsStale
)
// balance calls to start/stop accessing securely scoped resource
let didStartAccessing = resolvedUrl.startAccessingSecurityScopedResource()
defer { resolvedUrl.stopAccessingSecurityScopedResource() }
print(resolvedUrl)
if !bookmarkDataIsStale && didStartAccessing {
print("bookmark is _not_ stale.")
print("resolvedUrl: \(resolvedUrl)")
completion?(resolvedUrl)
} else {
// resolve if bookmark is stale. untested.
print("bookmark is stale. renewing.")
let resolved = try resolvedUrl.bookmarkData()
print(resolved.description)
}
} catch {
print("Error: \(error)")
}
}