Function to clear complete cache and logs in iOS - ios

My iPhone regularly consumes all of the 64GB, most of it by something called 'other'. I tried every trick I could find on the Internet, but nothing seems to help. None of the installed apps take up this memory, so I guess most of the 'other' is by something internally in iOS. The only way I could find to get rid of most of the 'other' is to make an iCloud backup. Unfortunately that doesn't work when you don't have a WiFi connection.
Therefore, I am thinking of writing an app that performs the same cleanup, but without making the backup of course.
Which iOS function can be used to perform this cleanup?

Related

iOS: Is it necessary to remove Firebase observers?

Why should I remove firebase references observers? I'm ok if all references get observed as long as the app is running. I'm not sure if references will still be observed after the user leaves the app, but if memory is only consumed while the user is using the app, why bother remove the observers? Especially if the data is mostly light weight texts.
I've looked into firebase documentation and there is no clear info about it.
There are several snippets saying that is a good practice to remove them on the opposite method you created them.
If you create them on onCreate, remove them on onDestroy. If you created them on viewWillAppear, remove them on viewWillDisappear.
In my experience I found out that is less cpu demanding to just leave them around if they are not firing very often. I have several observers on my app it's less cpu intensive to just quit the app than to remove them.
The case is not what can happen if the user leaves the app, after it's closed/killed it'll not be observed anymore. Neither is a problem because of CPU or internet usage, since you'll get light weight texts. The case is what can happen if the user is using the app and an observable is fired.
Let's say that in your app's home page you'll have an observable sending the user to a specific page if a value on the user's node changes, and if in the middle of the usage this value changes the user may be redirected to another page without knowing what happened, so bad UX.
Something that happened to me was leaving observables and them i signed out of my account, my app broke because there was no user connected, therefore i wasn't able to observe a node where i needed to be authenticated to query a value.
So that's why you should remove every observable as you go off a page or when quiting the app or signing out, because it can give the user some errors or uncommom behaviours that'll make them think that the app is broken or is not a good app.
Hope this helps :D

iOS persistent cache directory

My app downloads data from the internet and then stores it somewhere on the device, so when the user has no internet connection the data will still be available. I know about the cache folder, but according to Apple this directory will be removed if the device runs out of disk space. This is really a problem for my app, since this might break the app for users with low disk space and a bad internet connection.
My question: Where do I save those files without the risk of them being deleted by the system due to low disk space or whatever. I can't place it in the documents directory because Apple will reject my application.
I have tried storing it in the documents folder, and then using the following line of code to disable iCloud backups.
try? NSURL.fileURLWithPath(self.path).setResourceValue(true, forKey: NSURLIsExcludedFromBackupKey)
But that doesn't work at all, it returns "()".
From the doc:
HANDLING ERRORS IN SWIFT: In Swift, this method returns Void and is
marked with the throws keyword to indicate that it throws an error in
cases of failure.
So () is the expected result. The real test of "working" is whether the file contents are retrievable and whether they don't synch to the cloud.
As an aside, I like better your original idea to use the NSCaches directory. It is exactly for content that can be regained with a fetch, but too expensive to fetch all the time. And having it emptied to keep the device running well sounds like exactly the right behavior.
The requirement that you've given yourself to deliver rich content, have a low memory impact on the device and work well with little or no network is a commendably high bar... too high in my opinion, compared to anyone else.
It seems to me reasonable to detect a no cache, low memory, disconnected situation and just apologize to the user. Tell them its their fault.

Syncing a local sqlite file to iCloud

I store some data in my iOS app directly in a local .sqlite file.  I chose to do this instead of CoreData because the data will need to be compatible with non-Apple platforms.
Now, I'm trying to come up with the best way to sync this file over iCloud.  I know you can't sync it directly, for many reasons.  I know CoreData is able to sync its DBs, but even ignoring that using CD would essentially lock this file into Apple platforms (I think? I've only looked into CD a bit), I need the iCloud syncing of this file to work across ALL of iCloud's supported platforms - which is supposed to include Windows.  I have to assume that there won't be any compatibility for the CoreData files in the Windows API.  Planning out the best way to accomplish this would be a lot easier if Apple would tell us any more than "There will be a Windows API [eventually?]"
In addition, I'll eventually need to implement at least one more sync service to support platforms that iCloud does not.  It would be helpful, though not required, if the method I use for iCloud can be mostly reused for future services.
For these reasons, I don't think CoreData can help me with this.  Am I correct in thinking this?
Moving on from there, I need to devise an algorithm for this, or find an existing one or an existing 3rd party solution.  I haven't stumbled across anything yet. However, I have been mulling over a couple possible methods I could implement:
Method 1:
Do something similar to how CoreData syncs sqlite DBs: send "transaction logs" to iCloud instead and build each local sqlite file off of those.
I'm thinking each device would send a (uniquely named) text file listing all the sql commands that that device executed, with timestamps.  The device would store how far along in each list of commands it has executed, and continue from that point each time the file is updated. If it received updates to multiple log files at once, it would execute each command in timestamp order.
Things could get 'interesting' efficiency-wise once these files get large, but it seems like a solvable problem.  
Method 2:
Periodically sync a copy of the working database to iCloud.  Have a modification timestamp field in every record.  When an updated copy of the DB comes through, query all the records with newer timestamps than some reference time and update the record in the local DB from the new data.
I see many potential problems with this method:
-Have to implement something further to recognize record deletion.
-The DB file could get conflicts. It might be possible to deal with them by handling each conflict version in timestamp order.
-Determining the date to check each update from could be tricky, as it depends on which device the update is coming from.
There are a lot of potential problems with method 2, but method 1 seems doable to me...
Does anyone have any suggestions as to what might be the best course of action? Any better ideas than my "Method 1" (or reasons why it wouldn't work)?
Try those two solutions from Ray Wenderlich:
Exporting/Importing data through mail:
http://www.raywenderlich.com/1980/how-to-import-and-export-app-data-via-email-in-your-ios-app
File Sharing with iTunes:
http://www.raywenderlich.com/1948/how-integrate-itunes-file-sharing-with-your-ios-app
I found it quite complex but helped me a lot.
Both method 1 and method 2 seem doable. Perhaps a combination of the two in fact - use iCloud to send a separate database file that is a subset of data - i.e. just changed items. Or maybe another file format instead of sqlite db - XML/JSON/CSV etc.
Another alternative is to do it outside of iCloud - i.e. a simple custom web service for syncing. So each change gets submitted to a central server via JSON/XML over HTTP, and then other devices pull updates from that.
Obviously it depends how much data and how many devices you want to sync across, and whether you have access to an appropriate server and/or budget to cover running such a server. iCloud will do that for "free" but all it really does is transfer files. A custom solution allows you to define your syncing model as you wish, but you have to develop and manage it and pay for it.
I've considered the possibility of transferring a database file through iCloud but I think that I would run into classic problems of timing - slow start for the user - and corrupted databases if the app is run on multiple devices simultaneously. (iPad/iPhone for example).
Sooo. I've had to use the transaction logs method. It really is difficult to implement, but once in place, seems ok.
I am using Apple's SharedCoreData sample as the base for this work. This link requires an Apple Developer Account.
I did find a much much better solution from Tim Roadley however this only works for IOS and I needed both IOS and MacOS.
rant> iCloud development really has to get easier and more stable! /rant

What actions are required when your app get an applicationWillResignActive call?

This question io3->ios4 upgrade said to support applicationWillResignActive. While implementing this call, I also implemented applicationDidEnterBackground and applicationWillEnterForeground. However, I found that my app would crash. After some debugging on the simulator I determined that I needed to reinitialize a key data structure in applicationWillEnterForeground. So my question is how would I have known that from reading the documentation? (In fact, I may be doing the wrong thing and just so happened to get it working again.) Is there an exact description of what to do when these methods are called?
Thanks.
The only things you should do when supporting multitasking, is saving the state of your app when it enters the background, and reload it when it becomes active. (If you generate a new template in Xcode, you'll see this.)
Saving state means writing any user preferences or data to disk. Reloading the state involves reading saved preferences and data, recreating any in memory data structures that might need it (like in your example you gave).
In most circumstances, there's little else you need to do. The only thing that would crash your app that is unique to multitasking would be trying to run code in the background for longer than the allotted amount of time, (which is 10 minutes.) Otherwise, it sounds like you have got other problems with your code.

SQLite Persistence throughout app lifecycle on iOS

I've been reading up on SQLite3 included in the iOS firmware which might serve my needs for the app i'm writiung.
What I can't figure out is if it is persistent or goes away like some objects do.
For example if I do sqlite3_open() which appears to be a C function rather than an Objective-C object, if I open this at the start of my application, will it stay persistent until I close it no matter how many views I push/pop all over the place.
Obviously that would depend on where I put it but if I was doing a universal app and had some central functions for loading / saving data which were common to both iPhone/iPad, if, in my didFinishLoading: I put a call to open the SQLite database and then called various exec's of queries, would it remain persistent throughout the lifecycle of the application.
or
Am I better off opening and closing as needed, i'm coming from a PHP background so i'd normally open a database at the start of the script and then run many queries and then finally close it before browser output.
From the 1,000,000th i've learned over the last few months about iOS programming, I think the latter might be the better way as there's possibility of app exit prematurely or it going to background.
I'd just like a second opinion on my thinking please.
I dont know directly, but I think you are right - you only need to open it once at the start of your app.
Looking at sqlitepersistentobjects, an ORM framework for iOS, it only opens the DB when its first used, and never closes it except when there is a problem opening it :)
Single opened sqlite database used throughout the app from different places in your app is fine.
You are using word "persistent" which is confusing. What you mean is "reuse of single connection, for executing different statements in the app, possibly from different threads". Persistence has completely different meaning in context of databases - it means that the requested modification of data has been safely stored to media (disk, flash drive) and the device can even unexpectedly shut down without affecting written data.
It's recommended to keep running sqlite statements from a single, dedicated thread.
It's not recommended to connect to sqlite database from different processes for and executing parallel modifications.
A good alternative solution is to use sqlite async extension which sends all writes to a dedicated, background thread.
You can check out https://github.com/mirek/CoreSQLite3 framework if you want to use custom built (newer version) of sqlite.

Resources