Parse app using huge (2+GB) storage size in PFFileStaging folder - ios

We're using Parse in our iOS app and we've discovered that our app is using an enormous amount of space -around 2.3GB in some devices- in storage. After downloading app data to my Mac, I've realized almost all of that data is the cached images in a folder called PFFileStaging, it contains highest resolution PNGs of all the PFFiles that the user has viewed in our app, ever. How can we disable this behavior, at least limit it? Is that the intended behavior? I heavily doubt using GBs of space is the intended behavior. Is this a bug?

Unfortunately this is not cache related (as per Parse's engineers: "this is used to ensure that no concurrent modification happens to the file after you request uploading").
They're planning to implement automatic trimming of PFFileStaging folder on every app start (as per road plan this should appear in next version 1.8.2).
See the the whole thread on GitHub.

Related

Best Practices / Solution Architecture on initial Icons Delivery to Mobile App in React Native

here is a question from a total beginner in mobile app development :)
I am building a React Native application for iOS platform first. I am stuck with decision on how to deliver icons to the application. Imagine:
I have a reference data set with eg travelling options (bike, motorbike, etc).
The actual set is much bigger though - I am expecting rather 100-200 items with one icon each for the UI.
These should be cached in the application.
Most of them wont change, new ones might come to the set periodically, but not even every week.
Now to the options I was thinking of:
Deliver a sqlite database with images as BLOB and update the database when new icons arrive
Deliver a sqlite database with image URLs for S3 bucket items and update the database when new icons arrive
Deliver the app with initial sqlite bundled with BLOB or URLs(?) and update over the air when new icons arrive
Do not use sqlite database at all and deliver all with REST API call on startup with image URLs. Load images when needed and cache them. Update database with new icon URLs when new icons arrive.
I think I tend to be using Option 4 because it seems least heavy on the client - he can always download the icon whenever he needs one. But it also has a latency because of downloading the icon for the first time from private s3 bucket.
However I am missing real-world experience in mobile apps and probably missing important details. Hoping for some insight from experts. Thanks for any pro and con you can deliver on this options!
You are right, no database needed at all.
So basically you have to load those icons only once and cache them inside the app. You can you something like react-native-fast-image or do caching by yourself.
If URL of icon was changed - the new image will be cached.
So on real-world apps, you usually have the image placeholders (example below) or loaders (more rare).
If you have multiple types of vehicle, you can create multiple placeholders and show them unless the original image is loading/not available.
Using react native firebase storage and firestore is a good option. The images can be loaded remotely and the caching is done automatically

Clear Cache in iOS: Deleting Application Data of Other Apps

Recently, I have came across many apps which "Clear Cache" on iPhone. They also specify that you may lose some saved data and temp files.
What I know is that Apple doesn't allows you to access data of other Apps neither directory. So, how they are cleaning cache data? Can anyone put some light on it?
Reference: Magic Phone Cleaner
Power Clean
They simply fill the free space on iPhone temporarily with random data leaving the system with no free space at all.
This forces iOS to clear all temp data, caches and iCloud Photos -if you enabled storage optimization- to clear space. So basically they are tricking the system to force it to clear temp and cached data.
No app can access anything outside of it's sandbox environment. In other words, technically it's impossible to clean cache on an iPhone unless it's jailbroken. Most of these apps doesn't do what they say, they just give an illusion to user. Loading up the memory can force iOS to terminate other apps in the background but, I it's unlikely that it will give any performance boost.
It doesn't clear data in external apps, it clears external data left by apps. Clearing the cache basically deletes all the temporary files.

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 load bulk data onto iOS device

I have to load a lot of data onto an iOS device with 128GB storage, for use by my app. The data is around 2,000 files of around 40Mb each, total is around 80GB - 100Gb.
I control the iOS device and the load machine/program and the local network they're on, and time is not critically important (if it takes a week to load, that's OK). I can format the data as required to facilitate the load.
I've done some iOS programming, but I'm not sure where to start looking for a solution to this. If you can outline the broad approach to use and which iOS docs to read up on, that's all I need.
Hoping for a solution where I can format the data and write the program, plug the iPad in to the Mac and say 'start loading' and come back when it's done.
We discovered that it is possible to load data one device at a time using iTunes, but that isn't a good answer for us.
We added a 'load data' button into the application. When triggered it loads a configuration file from a hard coded local network address, then retrieves all the data files listed in the configuration file using REST GETs from the local server, storing them into the application /Documents directory.
This is a good approach for us; it is secure, allows multiple devices to load data at the same time, and doesn't need any manual file loading : start the app, press 'load', and wait for it to finish.

Does the "do not back up" attribute work on data in 'Library/Caches'

Apple's data storage guidelines state the following:
2) Data that can be downloaded again or regenerated should be stored
in the /Library/Caches directory.
...and (emphasis mine):
4) Use the "do not back up" attribute for specifying files that should remain on device, even in low storage situations. Use this attribute
with data that can be recreated but needs to persist even in low
storage situations for proper functioning of your app or because
customers expect it to be available during offline use. This attribute
works on marked files regardless of what directory they are in,
including the Documents directory. These files will not be purged and
will not be included in the user's iCloud or iTunes backup. Because
these files do use on-device storage space, your app is responsible
for monitoring and purging these files periodically.
The page that Apple links to with a more detailed discussion of this topic does not mention anything about the attribute doing anything to prevent cached data from being purged.
So does anyone know if the "do not back up" attribute actually works like "do not backup and do not delete" for items placed in /Library/Caches, or if files still need to be stored inside of the application's Documents directory to ensure that they are not deleted when the device is running low on space?
I've made a quick test on iPhone 5 iOS 7.1.1:
I put some files to “/Library/Caches” (NSCachesDirectory) and mark them with NSURLIsExcludedFromBackupKey attribute. Then I put some more big files to the same directory in a normal way.
I then made a low disk space warning by taking a long video with the camera app.
After the warning, files marked with “do not backup” was not deleted from Cache, but the other files was! So, this attribute is really working and made two different things in spite of its name – excludes from backup and preserves from being purged on low space warning.
To me this is very clear, and the directory structure is the one I would follow first, just as Apple says. If you both want to save the file and not back it up, put it in Documents, preferably in a folder that you mark.
Even if you observe some behavior today using Caches, it may change in the future.
Currently researching this same question and also made the assumption that adding that attribute will prevent a file from being purged in a low disk space scenario (You know, because apple's documentation literally says that). I thought I would update this with my findings since it has been a few years since the accepted answer. I have a database that can be recreated and contains no user generated data, so I store it in caches, but contains some data that can affect the proper functioning of the application, so I don't want it to be purged when running out of disk space (currently happening and logged as a bug). I have experimented with adding the NSURLIsExcludedFromBackupKey to the file itself and file is still being removed after purge happens. So it does not seem to prevent purge as of iOS 11.3. Not sure what the next move is as I really don't want to move the database for all our users, but that's probably the next step so it will be safe in Documents. Please correct me if someone has a different experience.

Resources