iOS11: Can't create folder again in iCloud drive once deleted manually - ios

I have developed an app for saving a file to iCloud drive from the app.
I am saving a file from my app to iCloud drive. So its working as expected. Its creating my app folder with saved file in iCloud drive app.
But if I delete the folder and try to save the file again from my app,
its giving an error as below :
"file.txt" couldn't be moved to "Documents" because either the former doesn't exist, or the folder containing the later doesn't exist.
This issue I'm facing only in iOS11. In iOS 10 its working properly.
How to fix this issue. Thanks in advance.

I found that you need to re-create the folder if it gets deleted, it won't create it automatically. So I'd try this:
let fileManager = FileManager.default
let iCloudPath = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("DirectoryName")
do {
// Try to create the file here
} catch let error {
// If that operation fails, you print the error and create the folder again
print(error.localizedDescription)
do {
try fileManager.createDirectory(atPath: iCloudPath!.path, withIntermediateDirectories: true, attributes: nil) }
catch let error {
print("Unable to create directory \(error.localizedDescription)") }
}

Related

Save file using Swift and iOS

I have an iOS app and I need to be able to pick a file on my iCloud Drive, modify the file, and save the modified file with a new extension. I've tried lots of things but I still can't write the new file. Here is my latest code:
documentPickerViewController = DocumentPickerViewController(documentTypes: ["public.item"], in: .open)
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
let fileURL = urls[0]
do {
// Read the file
_ = fileURL.startAccessingSecurityScopedResource()
let fileData = try Data(contentsOf: fileURL, options: .uncached)
fileURL.stopAccessingSecurityScopedResource()
// write the file
let fileCopyURL = fileURL.appendingPathExtension("copy")
_ = fileCopyURL.startAccessingSecurityScopedResource()
try fileData.write(to: fileCopyURL)
fileCopyURL.stopAccessingSecurityScopedResource()
}
catch {
print(error.localizedDescription)
}
}
When I pick a file on my iCloud Drive I get the following error:
You don’t have permission to save the file “TestFile.txt.copy” in the folder “Test Files”.
How can a save the modified file?
First, I think you should make sure that you have the correct entitlements/permissions to write to iCloud Drive:
If this still doesn't work, try updating the CFBundleVersion or Build Number of your app and make sure that your Bundle Identifier (in the first section of Signing & Capabilities) is correctly registered on your Apple Developer account.
According to your code, what you're trying to accomplish is feasible but the issue comes from elsewhere.
Let me know if you have an issue following these steps. Good Luck!

Where is the right place in the project to put a resource text file to read in an iOS App?

I'm trying to read a text file in a new App, but when it runs the file cannot be found.
I'm not sure where in the project I should put the file. I dragged it into the Assets folder from finder, but it's still not found. I looked at a similar question but the answer was in a much older version of Xcode and didn't solve my problem. I'm using Xcode 11.1
if let filepath = Bundle.main.path(forResource: "BibleTable", ofType: "csv") {
do {
let contents = try String(contentsOfFile: filepath)
print(contents)
} catch {
print("Error reading file BibleTable.csv")
}
} else {
print("File not found")
}
It gives "File not found"
Anywhere you fancy in the Bundle other than the assets folder, just as long as you your app (and any test target) is selected as a target in the File Inspector's Target Membership component.

Alternative UIActivityViewController save dialog for Mac Catalyst or solution for UIDocumentPickerViewController throwing error code 260

I am looking for an alternative export menu other then UIActivityViewController for a Mac Catalyst app. While this works, the user can not choose where they want to save the file (the file is a JSON file of all the items in a list) and I would like the user to be able to choose the directory they want to save the JSON to. I have tried the following code but it gives the error "Error Domain=NSCocoaErrorDomain Code=260 'The file 'name.json' couldn’t be opened because there is no such file'" when you try to save a file.
The Code:
let fileManager = FileManager.default
do {
let fileURL2 = fileManager.temporaryDirectory.appendingPathComponent("\(detailedList.lname!).json")
// Write the data out into the file
try jsonData.write(to: fileURL2)
// Present the save controller. We've set it to `exportToService` in order
// to export the data -- OLD COMMENT
let controller = UIDocumentPickerViewController(url: fileURL2, in: UIDocumentPickerMode.exportToService)
present(controller, animated: true) {
// Once we're done, delete the temporary file
try? fileManager.removeItem(at: fileURL2)
}
} catch {
print("error creating file")
}
I have tried Googling other ways or ways to get this to work but I cannot find anything that will work on Mac Catalyst. I know you can do this because I have seen other apps and examples do it but nothing works for me. So what would be a possible alternative way of doing this or a solution to this code?
The problem is that you are removing the file you wish to save before the user has a chance to choose where they want to save it.
The completion handler where you call try? fileManager.removeItem(at: fileURL2) is called as soon as the document picker is displayed.
The proper solution is to delete the file in the UIDocumentPickerDelegate methods, not when the picker is presented.

NSFileManager moveItem throws Error Code=513

I'm trying to move a file from a URL to another, however I get an error with code 513. I understand that this is a NSFileWriteNoPermissionError. I don't see how this possible considering I created the folder in the first place.
//self.video!.folderURL.path = /var/mobile/Containers/Data/Application/066BDB03-FD47-48D8-B6F8-932AFB174DF7/Documents/AV/769c504203024bae95b47d78d8fe9029
try? fileManager.createDirectory(atPath: self.video!.folderURL.path, withIntermediateDirectories: true, attributes: nil)
// Update permission for AV folder
do {
let parentDirectoryPath = self.video!.folderURL.deletingLastPathComponent().path
let result = try fileManager.setAttributes([FileAttributeKey.posixPermissions: 0o777], ofItemAtPath: parentDirectoryPath)
print(result)
} catch {
print("Error = \(error)")
}
// sourceURL = file:///private/var/mobile/Containers/Data/PluginKitPlugin/50D8B8DB-19D3-4DD6-93DD-55F37CF87EA7/tmp/trim.6D37DFD2-5F27-4AB9-B478-5FED8AA6ABD7.MOV
// self.url = file:///var/mobile/Containers/Data/Application/066BDB03-FD47-48D8-B6F8-932AFB174DF7/Documents/AV/0b0b6803e891780850152eeab450a2ae.mov
do {
try fileManager.moveItem(at: sourceURL, to: self.url)
} catch {
QLogTools.logError("Error moving video clip file \(error)")
}
Error
Error Domain=NSCocoaErrorDomain Code=513 "“trim.90A10B33-B884-419F-BAD9-65583531C3C3.MOV” couldn’t be moved because you don’t have permission to access “AV”." UserInfo={NSSourceFilePathErrorKey=/private/var/mobile/Containers/Data/PluginKitPlugin/0849234B-837C-43ED-BEDD-DE4F79E7CE96/tmp/trim.90A10B33-B884-419F-BAD9-65583531C3C3.MOV, NSUserStringVariant=(
Move
I tried altering the permission of the folder I created in the first place to 0o777, but when I print out its attributes it returns 511 as its permissions.
P.S:This only happens on iOS 13.
I solved my issue, but it may be different to what you were experiencing: I still had issues when changing to copyItem. I'm adding my findings here as an answer in case anyone else stumbles upon this question as I did and it helps them out.
My app loads custom files that can be downloaded from my website. With iOS 13's download manager, these are copied to the Downloads folder first, and can then be opened by my app. Yet my app was having permission errors when attempting to access these files in the same way as iOS 12.
This answer to a different question clued me in. I need to call startAccessingSecurityScopedResource() and stopAccessingSecurityScopedResource() as follows:
// source and destination are URLs
if source.startAccessingSecurityScopedResource() {
try FileManager.default.moveItem(at: source, to: destination)
}
source.stopAccessingSecurityScopedResource()
The Apple documentation doesn't really suggest that this is new with iOS 13 but I think just the different approach to file downloading means sandboxing considerations need to be made.

realm.io writeCopyToPath ? what's the inverse operation?

so I have some realm swift code:
let realm = Realm()
realm.writeCopyToPath(tempfile! , encryptionKey: nil)
let newasset = CKAsset(fileURL: NSURL(fileURLWithPath: tempfile!, isDirectory: false))
and then I save off the newasset to cloudkit...
but when I bring it back,
let defaultPath = Realm().path
var someError: NSError?
NSFileManager.defaultManager().removeItemAtPath(defaultPath, error: &someError)
if someError != nil {
println("Error removing realm file, \(someError)")
}
NSFileManager.defaultManager().copyItemAtPath(asset.fileURL.path!, toPath: defaultPath, error: &someError)
if someError != nil {
println("Error copying realm file into place, \(someError)")
}
it does not seem to work... I'm wondering if there is another way to bring back the realm file and place it where realm expects it?
The default location and file name of the default Realm file is default.realm, located in the app's Documents directory. As long you've correctly copied the Realm file out of CloudKit and to that location with the proper file name, accessing that file via calling Realm() should just work straight out of the box.
It sounds like you've got a few points in here that you can potentially test to see if anything is failing:
1) Make sure the duplicate Realm file is being created properly.
2) Ensure the file is uploaded to CloudKit properly, without fail.
3) Ensure the file came back down from CloudKit properly without any errors.
4) Double-check that copying the file from CloudKit to the default Realm file path succeeded.
If that all didn't work, please let me know here what sort of error you're specifically getting. Thanks, and good luck!

Resources