I got little problem, I am downloading PDF and saving to location, I am using write method to save to location and everything seems to work on version iOS 10 and below, but I got problem with iOS11, I am getting false from method below, I checked path, and bytes and it is same on both devices.
(try? data.write(to: invoiceFileUrl, options: [.atomic])) != nil
try this
let data = NSData(contentsOf:url! as URL)
data?.write(to:invoiceFileUrl, atomically: true)
Have you tried simply moving the file around? I am guessing you are using URLSession to download said file ( or you should anyway ).
Then you can use FileManager to move the temporary file to your documents or whatever desired directory in your app's container.
FileManager.default.moveItem(at:temporaryURL, to: destinationURL)
In case you prefer using paths there is also:
FileManager.default.moveItem(atPath: temporaryPath, toPath: destinationPath)
Though I personally don't use paths often (anymore) because it can lead to a whole load of inconsistencies and other issues you just don't want to deal with. Whatever backend you have try to move to NSURL or URL as quickly as you can with any received data; it'll make your life easier and most importantly more consistent accross foundation API's.
moveItemAtURL - Foundation documentation
Related
Background
I've written one particular app via Windows Forms (C#), Android (Java and Kotlin), HTML5 Web App, ElectronJS (runs on Linux, Mac, and Win10) and even as a UWP (Universal Windows Platform) app.
All Use JSON File For Data
All of those apps use the exact same JSON formatted data for user settings.
That means I can share data on all platforms via the same file and file format.
On Android there is the additional benefit of having the file saved in the UserPrefs (which provides security and backup for user).
The Problem
I've also written the app as an iPhone/iPad app (Swift), however I cannot find the proper way to handle the JSON file storage.
The problem is not related to de-serializing the JSON into my business object. That all works fine. However, I am not sure about:
where should files be stored in the iPhone/iPad system?
can you save a file in some sort of user preference or appdata
location?
How do you open a file for read/write and read/write data? (Swift)
How can I better understand the paths available to read and write
files?
I've searched all over looking for this answer. Can you point me to official documentation, a book, a StackOverflow item or something that explains this clearly? (Hopefully with Swift examples.)
See iOS Storage Best Practices video and the File System Basics document. That should get you going.
In short, app data is generally stored in “application support directory”, documents exposed to the user (e.g. the Files app) are stored in “documents” folder, downloads that can be easily re-retrieved are stored in “caches” folder. Technically you could use UserDefaults for storing of this sort of application data, but it really is not intended for this purpose.
Re opening a file for “read/write”, when dealing with JSON, you don’t generally do that. You read the file into a Data and deserialize the JSON into your model objects.
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("appdata.json")
let data = try Data(contentsOf: fileURL)
let appData = try JSONDecoder().decode(AppData.self, from: data)
// do something with appData
} catch {
print(error)
}
When you want to update, you serialize the model objects into a Data containing your JSON and then write it to the file, replacing the file.
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("appdata.json")
let data = try JSONEncoder().encode(appData)
try data.write(to: fileURL)
} catch {
print(error)
}
Obviously, this assumes that the AppData type (or whatever you call it) conforms to Codable, but you said you were familiar with serialization of JSON. See Encoding and Decoding Custom Types for more information.
I am very new to this IOS swift programming. So need some suggestion and help. I am creating an app in which I have to show different file coming from the server. Below is the kind of link from which my file data is coming.
http://demo.xxxx.com/dctm-rest/repositories/iol_ref2/objects/0900a18480383d14/content-media?format=pdf&modifier=&page=0
This above link is for pdf or it can be of any type (txt, doc, img etc) so I have tried so many things but I was unable to get a result.
Solutions What I have tried:-
With basic auth, I am requesting URL and getting contents from the file, so I was getting data from server and printing on console but when I tried to copy that contents to one file it says unable to copy says no such file or folder exist but I have properly defined the path location. Below is my code link which I have asked earlier.
How to read data from file placed in server through url link in ios swift (4)?
Someone suggested using Alamofire lib that also I have used but no luck. Below is the code which I have referred.
Alamofire: finished with error - code: -1001
So let me know what I am doing is correct or not or is there any new method or way I can try. I have tried web view too. So please help me with this.
Thanks in advance
I use code like this to download a file and store it locally.
let destination: DownloadRequest.DownloadFileDestination = { _, _ in
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let fileURL = documentsURL.appendingPathComponent(documentFilename)
return (fileURL, [.removePreviousFile])
}
Alamofire.download(url, to: destination).response { [unowned self] response in
// check download and call completion handler
}
What code did you use to download the file?
I am trying to decompressed a Json data stream. I've found various decompression solutions, the native zlib seems easier, the other cocoa pod solutions produced new problems. The setting advised in native zlib inflate/deflate for swift3 on iOS seems working, the problem is what's next. I've thoroughly searched the net, only found C or Obj-C example codes but not Swift's. Thanks.
Another solution I tried was with https://github.com/mw99/DataCompression. But I had problem trying to set it up according to the instruction so look into the short codes and took out the part that I think should work for me, hard-coded some of the options. But no matter which algorithm I tried, perform() return nil.
I also tried unzip(), it failed at guard header >> 8 & 0b1111 == 0b1000. The web address automatic download a gzip file which can be decompressed into a Json file.
var routeFile: JsonRouteFile?
UIApplication.shared.isNetworkActivityIndicatorVisible = true
let urlRoute:URL = URL(string: "http://data.taipei/bus/ROUTE")!
DispatchQueue.global().async {
do {
let data:Data = try Data(contentsOf: urlRoute)
routeFile = try JSONDecoder().decode(JsonRouteFile?.self, from: data.decompress()!)
`
https://github.com/1024jp/GzipSwift works.
I didn't go through the enter installation though. Just dragged the file over.
I am trying to use a bundled realm file without success. I know that my realm file was copied successfully to my application’s Directory but I ca not read it.
fatal error: 'try!' expression unexpectedly raised an error: "Unable
to open a realm at path
'/Users/…/Library/Developer/CoreSimulator/Devices/…/data/Containers/Data/Application/…/Documents/default-v1.realm'.
Please use a path where your app has read-write permissions."
func fullPathToFileInAppDocumentsDir(fileName: String) -> String {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,NSSearchPathDomainMask.UserDomainMask,true)
let documentsDirectory = paths[0] as NSString
let fullPathToTheFile = documentsDirectory.stringByAppendingPathComponent(fileName)
return fullPathToTheFile
}
In didFinishLaunchingWithOptions:
let fileInDocuments = fullPathToFileInAppDocumentsDir("default-v1.realm")
if !NSFileManager.defaultManager().fileExistsAtPath(fileInDocuments) {
let bundle = NSBundle.mainBundle()
let fileInBundle = bundle.pathForResource("default-v1", ofType: "realm")
let fileManager = NSFileManager.defaultManager()
do {
try fileManager.copyItemAtPath(fileInBundle!, toPath: fileInDocuments)
} catch { print(error) }
}
And setting the configuration used for the default Realm:
var config = Realm.Configuration()
config.path = fileInDocuments
Realm.Configuration.defaultConfiguration = config
let realm = try! Realm(configuration: config) // It fails here!!! :-)
As the documentation suggests, I have tried as well to open it directly from the bundle path by setting readOnly to true on the Realm.Configuration object. I am not sure if this is something related to Realm or if I am overlooking something with the file system…. I have also tried to store the file in the Library folder.
Realm 0.97.0
Xcode Version 7.1.1
I tried to open the realm file using Realm's browser app and the file does not open anymore. It has now new permissions: Write only (Dropbox). So, I decided to change the file permission back to read/write using file manager’s setAttributes method. Here is how I did it:
// rw rw r : Attention for octal-literal in Swift "0o".
let permission = NSNumber(short: 0o664)
do {
try fileManager.setAttributes([NSFilePosixPermissions:permission], ofItemAtPath: fileInDocuments)
} catch { print(error) }
The realm file can now be open at this path.
That exception gets thrown whenever a low level I/O operation is denied permission to the file you've specified (You can check it out on Realm's GitHub account).
Even though everything seems correct in your sample code there, something must be set incorrectly with the file location (Whether it be the file path to your bundle's Realm file, or the destination path) to be causing that error.
A couple of things I can recommend trying out.
Through breakpoints/logging, manually double-check that both fileInDocuments and fileInBundle are being correctly created and are pointing at the locations you were expecting.
When running the app in the Simulator, use a tool like SimPholders to track down the Documents directory of your app on your computer, and visually ensure that the Realm file is being properly copied to where you're expecting.
If the Realm file is in the right place, you can also Realm's Browser app to try opening the Realm file to ensure that the file was copied correctly and still opens properly.
Try testing the code on a proper iOS device to see if the same error is occurring on the native system.
If all else fails, try doing some Realm operations with the default Realm (Which will simply deposit a default.realm file in your Documents directory), just to completely discount there isn't something wrong with your file system
Let me know how you go with that, and if you still can't work out the problem, we can keep looking. :)
This will occur if you have your realm file open in Realm Studio at same time you relaunch your app. Basically in this case Realm can't get write permissions if Studio already has them.
To add to the solution based on what I've discovered, make note of what error Realm reports when it throws the exception, as well as the type of Error that is passed.
As of writing, Realm documents their errors here:
https://realm.io/docs/objc/latest/api/Enums/RLMError.html
What this means is that you can find out if your Realm file has permissions problems and react to those based on Realm passing you a RLMErrorFilePermissionDenied. Or if the file doesn't exist with RLMErrorFileNotFound.
The tricky thing I'm finding is when you get a more generic RLMErrorFileAccess, but that's for another question on Stack Overflow...
I had the same issue and tried too many ways to fix it. The easiest way to fix this problem is manually creation of the folder XCode cannot reach '/Users/…/Library/Developer/CoreSimulator/Devices/…/data/Containers/Data/Application/…/Documents/...' as explained at https://docs.realm.io/sync/using-synced-realms/errors#unable-to-open-realm-at-path-less-than-path-greater-than-make_dir-failed-no-such-file-or-directory
Once you created this folder and run the project, XCode creates the Realm files inside this folder automatically.
I would like to be able to redirect my logging statements to a file so that I can retrieve them when my app runs standalone (i.e. is not attached to Xcode). I have discovered (thank you Stackoverflow) that freopen can be used to accomplish this.
If I create a new Xcode project and add the code to redirect stderr then everything works as expected.
However, when I add the redirection code to my existing, bluetooth project I am having trouble. The file is being created and I can retrieve it using iTunes or Xcode's Devices window, but it is of size 0. If I explicitly close the file then the text that I wrote actually makes it into the file. It is as though iOS is not flushing the file when the app is terminated. I suspect that the trouble stems from the fact that I have enabled background processing. Can anyone help me to understand this?
Here is my code:
let pathes = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true);
let filePath = NSURL(fileURLWithPath: pathes[0]).URLByAppendingPathComponent("Test.log")
freopen(filePath.path!, "a", stderr);
fputs("Hello, Samantha!\r\n", stderr);
struct StderrOutputStream: OutputStreamType {
static let stream = StderrOutputStream()
func write(string: String) {fputs(string, stderr)}
}
var errStream = StderrOutputStream.stream
print("Hello, Robert", toStream: &errStream)
fclose(stderr) // Without this the text does not make it into the file.
I'd leave this as a comment, but have you looked into NSFileHandle? It sounds like you just need a way to append data to the end of a text file, correct?
Once you have a handle with something like NSFileHandle(forWritingToURL:), you can use .seekToEndOfFile() and .writeData(_:). As a side note, you'll need to convert your String to Data before writing it.
Admittedly, this will probably end up being more lines of code, and you'll almost certainly need to take threading into consideration.