Saving the state of a view after action executes - iphone

I was wondering how you would save the state of a view after it runs an action that leaves for another view then comes back?
Please Help

Store state variables in NSUserDefaults or use NSArchive / sqlite database. Depends on what kind of state information you wish to store. Always assume your previous view will 'unload' if a new view is loaded (using presentModalView or the UINavigationController). This way you're always prepared for the worst. Under low memory conditions the view currently not visible gets its 'view' unloaded and thus you must recover your previous state yourself (you could even simply use class variables if the first view isn't destroyed).

Related

How to preload data before moving to another VC

I have a method that reads some data from a database and returns it in a closure, for example:
DatabaseManager.readUser(withUserID: "Bob") { (user, error)
MySingleton.shared.user = user
}
I have a home VC which is my landing page, and a "user" VC that a user can navigate to. My user VC needs to display the data read from the database, in this case MySingleton.shared.user.
My problem:
I am currently trying to load the user's data on a background thread in my home VC, so by the time the user navigates to the user VC, the data can be displayed. However, if the user navigates to the user VC too fast, before the data was read, my app crashes because MySingleton.shared.user is nil, as expected.
My other option would be to load the data in viewDidLoad() in my user VC and display it after it was set in the closure. But this might cause there to be a kind of blank screen between the time the VC loads, and the time the data was read.
What is the best option here for a seamless user experience? Is there a way I can try to preload it in my home VC, and if its still not set by the time I navigate, wait until it is before displaying the user data?
If you want to start data loading when the screen is opened you can proceed in the following way:
On button tap check that you data is loaded. If yes - open the next screen, if no - set a flag (for instance openScreenOnDataLoad = true) and display a progress indicator.
In your closure when the data load is finished check that flag and open the next screen if the flag is set.
If you are initiating the data load in some other place/class you can use notification to inform other parts of the program that the data was loaded.
My general advice in these type of cases:
When Moving to a new ViewController, any required dependancies should be injected at the time of initialization/segue, and everything else should be handled internally during the ViewController's life cycle.
This makes the requirements for showing the ViewController clear, minimizes state complexity, and increases modularity.
In your case that means either the HomeVC needs to load the date (preferably indicating loading somewhere in the UI) and send it to the UserVC when it's made, or the UserVC will need to load the data and handle any loading UI there.
Personally I would prefer the second option minimize dependencies, simplifying navigating from anywhere else.
As an aside, if you're sure you want to use a singleton like that it's generally a good idea to handle the singleton management (creation, destruction) in the Model, and (at most) only access it from your ViewControllers

Create NSManagedObject in one view and save in another

I want to know what the best way to implement a certain functionality. I have a message composer view where the user creates a NSManagedObject MessageObject. I also have a class ObjectHelper which has a global instance initialized.
I have a background (private queue) NSManagedObjectContext create a MessageObject immediately when the user enters the compose view. The catch here is that the ObjectHelper (not the ComposerViewController) is the owner of this new object - it has a property variable with a strong reference:
ObjectHelper.h:
#property(nonatomic, strong) MessageObject *newObject;
Then, back in my ComposeViewController, I set a timer to save the object to disk every 30 seconds (this saves a draft, like auto-save, in case the user gets interrupted somehow or the application crashes, the data doesn't get wiped out).
Then, when the user hits the save button, I want to make sure I do as little work as possible on the main thread so that the dismiss modal view animation is smooth, and function returns to the main view controller quickly. So what I do is create an NSDictionary with all the values of the message object, call [globalObjectHelperInstance updateNewObjectInstanceWithDictionary:]
What this does is update the newObject instance that was already created in the beginning of the compose view with the values from the dictionary, and does it in the background thread.
Then I dismiss the modal.
I have a few questions here (please answer whatever you can):
Is there a better way to implement "draft" saving functionality rather than creating a property instance in the ObjectHelper? (the reason I create a property instance in an outside class other than the ComposeController is because the view controller dismisses while background work is being done on the object, so I'm afraid it will disappear from memory if I make it an instance variable.)
Should the property reference be a weak or strong? I know an NSManagedObjectContext is not guaranteed to retain its objects, unless (I think) these objects have pending, unsaved changes.
For some reason, calling [backgroundMOC obtainPermanentIDsForObjects:self.newObject error:&error]in the [globalObjectHelperInstance updateNewObjectInstanceWithDictionary:] before saving causes a EXC_BAD_ACCESS crash. I'm guessing this has something to do with the way I'm managing memory in my situation.
Your way to save draft seems very fine to me.
Another option is not to keep the property reference in any object and fetch the draft object by some key, update it and save it again. This might make sense in case you save something rarely or have something very big, but your current approach seems much more suited.
The reference should be strong. You want it to be present at all times while you want to update it, and you require its existence, so that qualifies for strong. In case of weak reference the object might get deleted. The object in the database on disk will remain, but your in-memory representation will be removed, you wouldn't want that—to update a nil reference.
I don't see any reason why this might cause any memory overuse or leaks, it's just one object and this isn't a case to be afraid of circular references.
As for your crash, it is hard for me to tell, but maybe you should obtain ID in the main thread's MOC at first, and then use it in the background MOC? Also, since it is easier to transfer NSDictionary between thread boundaries rather than an NSManagedObject, maybe you should keep your draft in the background MOC all the time?
Your code in the updateNewObjectInstanceWithDictionary: would then call a GCD block on the background queue and pass it the dictionary to save.

iOS Logout design

I have an app that has many web services and notifications going on. I need a logout feature. I wish there was a way simply to kill the app and restart it but there is not. Does anyone have some recommended guidelines on creating a logout function (it will take the user back to the login screen). The problem is there are notifs that should be unsubscribed from, views that should be removed, view controllers that I want to be released, then everything to reinitialize. That seems like a lot of work for a simple task. Any thoughts?
The first thing to make sure when terminating all requests is to change all delegates that are supposed to receive responses to nil. After you've taken care of this, you should indeed remove all irrelevant view controller's views from your root view (and release them if they are retained anywhere), and of course flush any existing data you don't need. If you design your MVC elegantly, you can achieve these actions without a lot of fuss, for example a ScreenManager Singleton class that manages all your view controllers should have no problem taking you back to the login screen while releasing any other view. A DataManager Singleton class that holds various data collections should have no problem removing any unneeded data entities and so on...

Block UITabBarController while contents of a view controller not been charged

I'm doing an app that uses a TabBarController and each Tab uses its own navigation controller.
The app has dynamic content and I use viewDidDisappear viewDidAppear methods to create or destroy the objects that I need each time I enter or exit into the ViewController.
My problem is when I start to sail very fast and I don't give time to load the Threads that I use for uploading content such as XML peta app or destroy objects when I leave the ViewController.
How I could control the tabs of the navigationbar or tabbarviewcontroller for not respond until the viewcontroller has loaded all contents?
Excuse me if I'm not well expressed. Thanks!
No matter you use synchronous request or asynchronous request, just show an UIAlertView while loading the data. This will both serve as a notification to the user that something is being loaded, and the it will block the interactions with all the other views on the screen.
As others have suggested in comments, I believe that what you want to do is rearrange the order in which things are triggered. Perhaps something like this:
On viewWillAppear:, clear (or disable or whatever is appropriate) your objects that are no longer valid and begin the load-new-content thread. Perhaps display a UIActivityIndicator or similar.
On viewWillDisappear:, tell the load-new-content thread that it can stop, its results are no longer needed. If you put up an activity indicator, take it down.
At the end of the load-new-content thread, take down any activity indicator, update the UI with the new contents and activate.
I don't really see any way around this -- if the UI is not valid until the new content is loaded, then you have to wait for it.
Another solution might be to cache the contents from the previous fetch, and always display those on viewDidLoad. Then, at the end of your new-content-thread, cache the new contents, and update the UI.

Skinning and caching user preferences

I have an application which allows customizing attributes such as background color, buttons, text (ie, titles), etc. In its current incarnation, viewDidLoad set the appropriate property on a UI widget by calling into a LookAndFeel class. LookAndFeel reads the user preferences.
Should each view perform a call into LookAndFeel, or should the Application fetch an attribute once and use the fetched value in all views? Is it OK to call getTitleColor once, hold it in the app delegate, and use it in every view?
That depends on how expensive your getTitleColor method is. If it's expensive, it should definitely be cached.
(Note: reading from a file or from NSUserDefaults could be considered expensive)