I've been using the new template for a document-based SwiftUI app. While you get a lot of file-management "for free" in the new template, as it stands in the iOS version users have to back out of the file to the file browser to change the filename. I want to create an opportunity for the user to rename the file while it is open.
Here's a sample project focused on the issue: https://github.com/stevepvc/DocumentRenamer
In the code, I've added to the template code a simple UI with a textfield for the user to enter a new name. When the user hits the "rename" button, the app checks to see if the URL with that name component is available, appending a suffix if necessary to create a target url.
It then attempts to rename the file, and this is when I am stuck. I have tried several methods, most recently the following:
But I keep getting the following error whenever I run the app on a device:
I have also tried this without the startAccessingSecurityScopedResource() check, and alternatively have tried creating a helper class as follows:
But using this method locks up the app entirely.
What is the correct method for renaming a file in the app's container, particularly using the new Swiftui Document based template?
Here's a sample project focused on the issue: https://github.com/stevepvc/DocumentRenamer
In the code, I've added to the template code a simple UI with a textfield for the user to enter a new name. When the user hits the "rename" button, the app checks to see if the URL with that name component is available, appending a suffix if necessary to create a target url.
Code Block func getTargetURL() -> URL { let baseURL = self.fileurl.deletingLastPathComponent() print("filename: \(self.filename)") print("fileURL: \(self.fileurl)") print("BaseURL: \(baseURL)") var target = URL(fileURLWithPath: baseURL.path + "/\(filename).exampletext") var nameSuffix = 1 while (target as NSURL).checkPromisedItemIsReachableAndReturnError(nil) { target = URL(fileURLWithPath: baseURL.path + "/\(filename)-\(nameSuffix).sermon") print("Checking: \(target)") nameSuffix += 1 } print("Available Target: \(target)") return target }
It then attempts to rename the file, and this is when I am stuck. I have tried several methods, most recently the following:
Code Block func changeFilename(){ let target = getTargetURL() var rv = URLResourceValues() let newFileName = target.deletingPathExtension().lastPathComponent rv.name = newFileName do { if fileurl.startAccessingSecurityScopedResource(){ try fileurl.setResourceValues(rv) fileurl.stopAccessingSecurityScopedResource() } } catch { print("Error:\(error)") } }
But I keep getting the following error whenever I run the app on a device:
Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “Untitled” in the folder “DocumentRenamer”."
I have also tried this without the startAccessingSecurityScopedResource() check, and alternatively have tried creating a helper class as follows:
Code Block class FileMover: NSObject { func moveFile(originalURL: URL, updatedURL:URL) -> Bool { let coordinator = NSFileCoordinator(filePresenter: nil) var writingError: NSError? = nil var success : Bool = true print("moving file") coordinator.coordinate(writingItemAt: originalURL, options: NSFileCoordinator.WritingOptions.forMoving, error: &writingError, byAccessor: { (coordinatedURL) in do { try FileManager.default.moveItem(at: coordinatedURL, to: updatedURL) success = true print("file moved") } catch { print(error) success = false } }) return success } }
But using this method locks up the app entirely.
What is the correct method for renaming a file in the app's container, particularly using the new Swiftui Document based template?