used disk space never released documents or/and shared container - ios

I am observing some strange behavior and am not sure what to make of it or how to get around it. The app may use a large amount of data and at some point GBs, I need to clear (delete) older data. I attempt to dynamically decide what and how much needs to be deleted.
The problem is that when I delete part or all of the data from the shared container, OS still reports that the app is using it. Restart did not help. Deleting the app solves the problem but given that I want to keep "newer" data and delete "older" data I do not want to delete the app. I also do not want the user to deal with this and want this to be done at the startup of the app.
Any suggestions?
Perhaps to make it more clear FileManager.default.removeItem(at: folderUrl) is used to remove folders/files. There is also trashItem method, but not sure it will change anything.
There are no errors, folders are deleted, yet OS reports space used by the app.
also may be similar to FileManager.default.removeItem not clearing storage

Related

How to best move a huge .sqlite database to a new directory on an old, low memory iOS device?

For my latest app update, I have to move the user's Core Data .sqlite database from the Documents directory to the Application Support directory. I use the migratePersistentStore:toURL:options:withType:error: method. I am dealing with one user who somehow managed to save enough data in her database so that it is now a whopping 9G. On top of that, her device is an iPad Air 1 - which had memory issues around the time it came out five or six years ago, and now it is 2018 and she is running the latest iOS. The migratePersistentStore:toURL:options:withType:error: method keeps crashing the app with low memory. But I have no other way to get the .sqlite to the necessary location. Can anyone advise me on how to best approach this situation? Ideally, something I could do in my code - but I would even appreciate suggestions on other ways I could just help the user to manually move that massive database at this point!
I guess you use migratePersistentStore because its the official way to do it. Its a good way, but sometimes you have to make your hands dirty:
Manually-moving database at app-start before you load it
This post shows that CoreData may use more than one file which you have to move. You can list the files in the directory, use a regex find all the files which have to be moved, move them to the new location and then load CoreData as usual from the new location.
This however requires there to be the necessary infrastructure in place to do this. You‘ll figure it out if you want to go this path.
You can hide this behind a feature-flag, only with a code, only for a certain user or after crashing with low memory so it doesn‘t impact users who don‘t need it.

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.

Lock file for editing in Dropbox

I am building app in iOS that saves data in Dropbox. Multiple device can use the same data. While doing this, sometime two device may overwrite same file. To avoid this situation is there any like lock file for writing.
Any alternative workaround solutions are also welcome.
While I don't know the Dropbox API, I would always be careful with a locking mechanism. I know from some systems, that the locks lead to a problem, if for example the app crashes or quits and the lock does not get released.
A very simple approach though would be to store the modification date when you have read the file. Then, before saving changes, compare your stored value with the most current one. If they are different, the file was modified. Next ask your users how to proceed and either commit the changes, cancel or create a new file with the same name and some appendix. That is how some sync clients I use are dealing with this problem.

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.

Good way to manage the Documents/Inbox folder in an iOS app

When a file is passed into an iOS application by the document interaction system, a copy of the file is stored in the application bundle's Documents/Inbox folder. After the application has processed the file, it obviously needs to remove the file from Documents/Inbox, otherwise the folder will continue to grow and waste storage on the device.
I am uncomfortable with this simple solution (A), however, because my app needs to interact with the user before it can finish processing and removing the file. If the user suspends the app during this interaction period, and the app then gets killed while it is in the background, the stale file will not be removed when the app starts up the next time. Of course I can improve my app to cover this scenario, but I suspect that there will always be another border case that will leave me with an "unclean" Documents/Inbox folder.
A preferrable solution (B) therefore would be to remove the Documents/Inbox folder at an appropriate time (e.g. when the app launches normally, i.e. not via document interaction). I am still uncomfortable with this because I would be accessing a filesystem path whose location is not officially documented anywhere. For instance, my app would break if in a future version of iOS the document interaction system no longer places files in Document/Inbox.
So my questions are:
Would you recommend solution A or B?
Do you use a different approach and can you maybe give an outline of how your app manages Document/Inbox?
Last but not least: Do you know a piece of official Apple documentation that covers the topic and that I have overlooked?
Since I have asked this question, I have implemented the following solution:
I have redesigned my app so that it now immediately processes a file handed over to it via documentation interaction, without involving the user at all. Unless the app crashes, or is suspended and killed, in the middle of processing the file, this should always leave me with a clean Documents/Inbox.
To cover the (rare) case of a crash or suspend/kill, my app removes the Documents/Inbox folder when it is launched normallly (i.e. without the purpose of document interaction). To achieve this the Documents/Inbox folder path is necessarily hardcoded.
Here are the thoughts that went into the solution:
Redesigning the app
Initially it seemed like a good idea to offer the user a choice how she wanted a file to be processed - after all, offering a choice would make the app more flexible and provide the user with more freedom, right?
I then realized that I was trying to shift the responsibility for deciding how document interaction should be handled to the user. So I bit the bullet, made the hard decisions up-front, and then went happily on to implement a simple and straightforward document interaction system in my app.
As it turns out, no user interaction also means that the app is easier to use, so here's a win-win situation, both for me as a developer and for the users of my app.
Removing Documents/Inbox folder during app launch
Removing the Documents/Inbox folder during app launch is just an afterthought, not an essential part of how my app handles document interaction
Therefore I am quite willing to take the risk that Apple might change the filesystem path of the inbox folder at some point in the future. The worst thing that can happen is that my app will start to accumulate a few files that are leftovers from crash or suspend/kill scenarios.
And finally, a few thoughts for further development:
If it ever turns out that there really should be more than one way how the app can handle document interaction, I would add a user preference so that the user has to make a decision up-front, and the app does not need to stop its processing to ask the user for a choice.
If it ever turns out that user interaction is absolutely unavoidable in the middle of the document interaction handling process, I would look at this approach: 1) Before the user is allowed to interact, move the file from Documents/Inbox to some sort of "staging" folder; 2) Let user interaction take place; 3) Process the file in the "staging" folder, in whatever way the user chose. The important thing here is that the "staging" folder is in a known location and is completely managed by the app. Should the user suspend and then kill the app in the middle of the user interaction step, an appropriate action can simply be taken when the app is launched for the next time.
EDIT
In iOS 7 it is no longer possible to remove Documents/Inbox once it has been created. The NSFileManager method removeItemAtPath:error: returns Cocoa error 513 which resolves to NSFileWriteNoPermissionError (cf. this list of Foundation constants). The error does not seem to be related to POSIX permissions, however, it rather looks as if the system itself interferes with the attempt at deletion (possibly protection of the app bundle structure?).
Also noteworthy is that nowadays Apple explicitly names Documents/Inbox in the documentation of the UIApplicationDelegate method application:openURL:sourceApplication:annotation:. They also say that
[...] Your app has permission to read and delete files in this directory but does not have permission to write to them. If you want to modify a file, you must move it to a different directory first.
There is more stuff about possible encryption of the files in the docs, but you should read up on that yourself.
This problem has become much more complicated with the introduction of the Files app, and the "Open in place" feature.
If you do not have "Supports opening documents in place" switched on, in your info.plist, then things are pretty much the same, and files opened from any other app still appear in the Documents/Inbox directory. But files opened from the Files app appear in another inbox, currently at tmp/<bundle ID of app>-inbox. It is still recommended to delete the file once you are done with it, but there is less need to occasionally clean the directory, because the tmp directory gets cleaned by iOS once in a while anyways.
If you do have "Supports opening documents in place" switched on, then things change drastically. Files opened from the Files app and some other apps are no longer copied into an inbox, but they are passed to you at their original location. That is typically some location inside the Files app itself, inside another app referenced from the Files app, or even some general iCloud location. If you expose the files in your Documents folder, then it could even be one of your own app's files.
Needless to say, if you get such a file, you must not delete it. But if the file comes in an inbox, which will still happen a lot as well, then you must delete it. In order to determine this, the options of the application:openURL:options: call contains an UIApplicationOpenURLOptionsOpenInPlaceKey key. If that has value (NSNumber) NO, then the file is in an inbox, and it should be deleted. It it has value YES, then it is opened in-place, and must not be deleted.
Note that for files that are opened in place, you also need to gain permission to use them first. You do that but surrounding the access to the file by startAccessingSecurityScopedResource and stopAccessingSecurityScopedResource calls. See Apple documentation for details.
I am just now facing this same problem. Like you I don't have a good solution but in response to your questions I'm leaning towards option A over option B because I don't like the idea of potentially having an issue with future releases of the OS. Since, in my case, there is no user interaction once I display the preview of the document, I can go ahead and delete it when when I receive the –documentInteractionControllerDidEndPreview: delegate callback. This is theoretical in that I haven't coded this yet and won't get to it for a while as it is a low priority item. If it doesn't work or there are other issues, I will report back here. The Google search I entered in order to find documentation from Apple pointed to this StackOverflow post. I haven't seen any other useful information from Apple or anyone else on the subject.

Resources