Clear All Documents and Data With Swift - ios

My app downloads and display GIFs from the Internet in UIImageViews. The GIFs don't need to be cached/saved at all. However, the app takes up lots of storage on the iPhone with Documents & Data being enormous.
I'd like to be able to clear the Documents and Data folder each time the user opens the app. Is this possible to do with Swift?

The extension you use uses the following code:
Data(contentsOf: url)
https://developer.apple.com/documentation/foundation/nsdata/1413892-init
This method will cache stuff in the system cache.
If you want to keep using that extension you should modify that code to use this one instead:
init(contentsOf:options:)
https://developer.apple.com/documentation/foundation/nsdata/1407864-init
And pass "uncached" as an option to avoid the cache.
https://developer.apple.com/documentation/foundation/nsdata.readingoptions/1412417-uncached
However I think that extension is poorly written, for instance, you should only use this method to load SHORT local files, for bigger files a stream is needed, for network requests you shouldn't be using it at all.
Important
Don't use this synchronous method to request network-based
URLs. For network-based URLs, this method can block the current thread
for tens of seconds on a slow network, resulting in a poor user
experience, and in iOS, may cause your app to be terminated. Instead,
for non-file URLs, consider using the
dataTask(with:completionHandler:) method of the NSURLSession class.
See URL Session Programming Guide for details.
Data(contentsOf: url, options: .uncached)

Related

Difference between three firebase storage download methods

I couldn't find resources discussing the difference between the three download methods in the firebase storage documentation and pros/cons of each. I would like some clarification about the firebase storage documentation.
My App
Displays 100 images ranging from 10 KB-500 KB in size on a table view
Will be used in a location where internet connection and/or phone service could be very weak
Could be used by many users
3 methods for downloading from Firebase storage
Download to NSData in memory
This is the easiest way to quickly download a file, but it must load entire contents of your file into memory. If you request a file larger than your app's available memory, your app will crash. To protect against memory issues, make sure to set the max size to something you know your app can handle, or use another download method.
Question: I tried this method to display 100 images that were 10KB-500KB in size on my table view cells. Although my app didn't crash, as I scrolled through my table, my memory usage increased to 268 mb. Would this method not be recommended for displaying a lot of images?
Download to an NSURL representing a file on device
The writeToFile:completion: method downloads a file directly to a local device. Use this if your users want to have access to the file while offline or to share in a different app.
Question: Does that mean all images from firebase storage will be downloaded on user's phone? Does that mean that the app will be taking up a large percentage of the available storage on the phone?
Generate an NSURL representing the file online
If you already have download infrastructure based around URLs, or just want a URL to share, you can get the download URL for a file by calling the downloadURLWithCompletion: method on a storage reference.
Question: Does this method require a strong internet connection and/or phone service connection to work?
Generally, your memory usage should not be affected by the method of retrieval. As long as you're displaying the 100 images, their data will be stored in the memory and should have the same size if they're identically formatted/compressed.
Either way you go with, I suggest you implement pagination (for your convenience, this question's answer might serve as a good implementation reference/guide) to possibly decrease the memory and network usage.
Now, down to comparing the methods:
Method 1
...but it must load entire contents of your file into memory.
This line might throw some people off thinking it's a
memory-inefficient solution, when all it really means is that you
cannot retrieve parts of the data, you can only download the entire
file. In the case of storing images, you probably would want that for
the data to make sense.
If your application needs to download the images every time the users
access it (i.e if your images are regularly updated), then this
method will probably suit you best. The images will be downloaded
every time the application starts, then they'll get discarded when
you kill it.
You stated that a part of your user base might have a weak internet
connection and so the next method might be more efficient and
user-friendly
Method 2
First off, the answers to your questions:
Yes. The images downloaded using this method will be stored on the users' devices.
The images should take up about the same size they're taking on Firebase storage.
Secondly, if you plan to use this method, then I suggest you store a
timestamp (or any sort of marker) in your database for when the last
change to the images occurred. Then, every time the app opens up, do
the following flow:
If no images are downloaded -> download images and store the database timestamp locally
If the local timestamp does not equal the timestamp on the database -> download images and store the new timestamp locally
Else -> use the images you already have, they should be identical to the ones in Firebase storage
That would be the best way to go if your network usage priority is
higher than that of the local storage.
And finally...
Method 3 (not really)
This is not a data download method, this simply generates a
download URL given a reference to the child. You can then use that
URL to download the data in your app or elsewhere as long as the used
app or API is authorized to access your Firebase storage.
Update:
The URL is generated from a Firebase reference (FIRDatabase.database().reference().child("exampleReference")) and would look like this: (Note: this is a fake link that will not actually work, just used for illustration purpose)
https://firebasestorage.googleapis.com/v0/b/projectName.appspot.com/o/somePathHere%2FchildName%2FsomeOtherChildName%2FimageName.jpg?alt=media&token=1a8f83a7-95xf-4d3s-nf9b-99a274927bcb
If you simply try to access that link you generate through any regular web-browser (assuming you don't have any Firebase rule that conflicts with that in your project), you can directly download that image from anywhere, not just through your app.
So in conclusion, this "Method" does not download data from Firebase storage, it just returns a download URL for your data in case you want a direct link.

How to handle large files with NSData?

I have a very large video and I need to chunk this video to upload it to Dropbox.
I tried to use NSData, but because this file is too large, my application always crashes, so I don't know what I can do now.
For smaller videos, I used this:
NSData(contentsOfURL: self.newAsset.URL)!.subdataWithRange(NSMakeRange(0, 10000000))
and I didn't have any problem with that, but when the video is too large I have an error:
Cannot allocate memory
So, what can I do to chunk the data of large videos?
For best practice go with NSURLSession if you want to implement custom otherwise lots for third party library are there like RESTKit or AFNetworking. For NSURLSession the session NSURLSession supports three types of tasks: data tasks, download tasks, and upload tasks. All it support the background uploads/downloads as well. source(apple developer)
Data tasks send and receive data using NSData objects. Data tasks are intended for short, often interactive requests from your app to a server. Data tasks can return data to your app one piece at a time after each piece of data is received, or all at once through a completion handler.
Download tasks retrieve data in the form of a file, and support background downloads while the app is not running.
Upload tasks send data in the form of a file, and support background uploads while the app is not running.
Image Source raywenderlich.com
You should use video file url to upload large data using NSURLSession
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL;

iOS How do I retrieve and store data from URL?

I am looking for best practices.
In my app, I send a request to my server for the URLs of the images I need to download and some meta data. I then need to store these images on disk. Once they are saved I have to update view. Storing on disk is also necessary for offline view so maybe I'll even have to store the file path to CoreData.
I think I can just use NSURLConnection to retrieve the image urls, then the images and then write them to disk. My concern is what should I do when the app is waiting for all this to occur? How do I know when to update, for example, a table? What if the user moves away and the view unloads? Just looking for advice.
Should I create a separate NSObject class to handle all this?
PS: How would I check for an existing internet connection before I do any of this anyway?
if you are already using CoreData, consider storing the images directly in the CoreData-DB. that depends on the size of the image, of course.
For synchronization of the db, this might be helpful: http://www.raywenderlich.com/15916/how-to-synchronize-core-data-with-a-web-service-part-1. They also use a separate class to handle this.
To check the internet connection, apple has a wonderful sample app:
https://developer.apple.com/library/ios/samplecode/Reachability/Introduction/Intro.html
EDIT: Oh, and NSURLConnection loads data asynchronously by default, so your app will stay responsive during data loading operations, you can handle the update-vioew-operations in the respective callback methods.
See the docs:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/
pay special attention to the difference between
sendAsynchronousRequest:queue:completionHandler: and
sendSynchronousRequest:returningResponse:error:

Download big file

I have a problem regarding the best approach to make an App that has to download and show pdf's, It is fed by a JSON that has links to 147 pdf files, sized between 1 and 2 MB.
Questions:
What is the best approach to download all the files to an iPad?
Shall I use AFNetworking 2.0?
Is NSFileManager the way to save all the files?
Problems I may encounter:
With an asynchronous download, if lost connection or no more space on the iPad, what are the counter mesures?
Are there tutorials or examples that deal with this situation?
Sorry for all the questions but I'm new to this.
Best Regards.
What is the best approach to download all the files to an iPad?
This is really broad as #rmaddy suggested. Specific questions are more easily answered. There are lots of ways you could download a file via an HTTP request to your device each with pros/cons depending on your situation.
Shall I use AFNetworking 2.0?
Sure. You'll get no argument from me. This is a widely used and solid API to interface with HTTP-based resources.
Is NSFileManager the way to save all the files?
Yes. NSFileManager is the class you use to read/write files from/to your app's sandbox.
With an asynchronous download, if lost connection or no more space on the iPad, what are the counter measures?
I'm not 100% certain so I can't speak to exactly what happens in this case. AFNetworking may provide some help by writing to a temporary file during a download, etc....
Are there tutorials or examples that deal with this situation?
I have a sample project on Github that shows a table of files that you can download. You can watch the progress of your downloads, pause each request, resume and cancel as well. When you're done you can view the file you downloaded. It uses AFNetworking and might be useful to you:
https://github.com/chefnobody/StreamingDownloadTest
When downloading large files, the main counsel would be to avoid trying to load these into memory as you download them. Instead, make sure you stream them directly to persistent storage. In terms of handling space-specific errors, just make sure you check NSError objects that are returned to you in completion handlers or the appropriate delegate methods.
If using AFNetworking, you can specify the outputStream of the AFURLConnectionOperation to reference a NSOutputStream that you create, referencing some path in your persistent storage.
See Memory pressure issue while downloading multiple files using AFNetworking for example.
Alternatively, you can use NSURLSession (whether via AFNetworking or you do it yourself) and instantiate a NSURLSessionDownloadTask, which does the same sort of thing.
Google "NSURLSessionDownloadTask example" and you'll find tons of references. The block-based rendition of downloadTaskWithURL is incredibly simple. To do background downloads is a little more complicated and requires delegate-based implementation (see Downloading Files and Handling iOS Background Activity sections of URL Loading System Programming Guide: Using NSURLSession or watch the WWDC 2013 video, What’s New in Foundation Networking.)
Either way, you avoid some of the memory consumption challenges associated with downloading large files.

Downloading large files

I am currently developing a application which has to be able to show offline videos which need to be downloaded first.
The problem was that these videos can be bigger that the memory that I can allocate to my application. So parts that are downloaded have to be saved immediately instead of saved in a NSData object. I'm hearing conflicting stories on whether or not RESTKit should work, and ASIHTTPRequest seems to be deprecated.
I will follow the suggestion from this thread as it seems to be the best option.
NSURLConnection download large file (>40MB)
Consider using NSURLConnection to download the video file and write the data directly to a file (NSFileHandle).
One advantage of using this method is that the NSURLConnection didReceiveData delegate method is continuously called as data is received, so you can update a progress bar.
Check out AFNetworking for network managing. I am not sure if they have video downloading, but the framework works great for images and other types of downloads that I have down before.
Without explaining all the hasle with dealing with HTTP responses by chunks and streams I would recommend using AFDownloadRequestOperation. It supports resuming downloads and has callbacks for showing download progress. I love it and use it in most of my projects.
P.S. It uses AFNetworking, which is a great framework for making all kinds of HTTP requests.

Resources