Where in my iOS (Swift) application lifecycle should i fetch all my data from firebase? - ios

User may not interact with my app, until all data is fetched from firebase. So my newbie plan so far is:
Start spinner
Fetch data from firebase (async)
When step 2 async job is completed, then hide spinner
My first thoughts as a newbie is often not the way to go and there must be a smarter way, where the framework is involved (maybe some place in app lifecycle) or a best practice pattern.
I can't find any useful stuff on www. A link can also be helpfull.

You should fetch your data in ViewDidLoad()
viewDidLoad()—Called when the view controller’s content view (the top of its view hierarchy) is created and loaded from a storyboard. The view controller’s outlets are guaranteed to have valid values by the time this method is called. Use this method to perform any additional setup required by your view controller.
Typically, iOS calls viewDidLoad() only once, when its content view is first created; however, the content view is not necessarily created when the controller is first instantiated. Instead, it is lazily created the first time the system or any code access the controller’s view property.
Your data will be fetched when you view in loaded.
If you want to refresh your data whenever your view gets diplayed then i use may use.
viewWillAppear()—Called just before the view controller’s content view is added to the app’s view hierarchy. Use this method to trigger any operations that need to occur before the content view is presented onscreen. Despite the name, just because the system calls this method, it does not guarantee that the content view will become visible. The view may be obscured by other views or hidden. This method simply indicates that the content view is about to be added to the app’s view hierarchy.

I would suggest you to create a view controller which is responsible to show the loading of the application and in background it syncs with your backend.
Having such a view controller along with loading indicator you can also show percentage progress for better UX.
Once the sync is complete you can navigate to home controller.
Secondly, If you are loading the same data again with another launch. add a sync check so as not the same data is downloaded again and again preserving app's time and space.

Related

Why doesn't fetched data disappear when returning to a view?

In my view controller's viewDidLoad method (which is only called once, unlike viewDidAppear), I'm making a network request for data. Whenever I switch views and return to the first view, I've noticed that even though data is not being pulled again, the old data still displays on the screen. I'm not using Core Data, so where is this data being stored? Why use Core Data if data is already persistent apparently?
If your views are embedded in a Navigation Controller or a Tab controller, then when you present another screen your first screen (and the Views and View Controller that make it up), are not taken out of memory, unloaded, destroyed, etc. The views are just rendered invisible (removed from view hierarchy). When you dismiss whatever "next" screen you're showing, you return back to the same still-existent original. It's re-displayed, not re-created. Everything about it's state is left exactly where it was at the point where you presented another view controller on top of it.

IOS - Disable View Cache in View Controller

I am pushing and popping from one view to the other within my App. The view is being retained in the memory so when you hit the "Back" button after pushing a view, the same screen that was before you pushed the view is retained.
For some reason, I will need to reload the parent view after popping from a child view. I need to display different content based on the actions the user taken when they were redirected to the child view.
I am using UINavigationController to navigate from one view to the other. I need it so I can easily go back and forth within the different views of the App.
The correct way to do this would be to perform your actions in viewDidAppear. Initialisation code that you write in viewDidLoad is called only once. But in viewDidAppear you can refresh your view's content every time the view is added to the window. The controller is retained in the memory for performance reasons. Removing it would hamper that factor.
Here is a stack overflow post that explains the different view* callbacks in good detail.

the Benifits of awakeFromNib?

I've been learning coredata by making a lot of simple test apps based on the xcode Navigation controller template with "use coredata" checked.
The awakeFromNib method in the App delegate has been a source of problems for me, because I'm adding other views to the controller and changing the load sequence, so that RootViewController may be a second or third choice.
I've figured out what awakeFromNib is doing, and I've removed it so the app delegate is no longer tied to any particular view. (So when I do want to load RootViewController, I'll load it as a regular view, and use its own viewDidLoad to initialize the managedObjectContext for the view).
My question: are there performance gains or other benefits by using awakeFromNIb in the AppDelegate? or is it just another way of doing the same thing as I'm doing from the viewDidLoad method?
All the methods fire at different times and different circumstances.
awakeFromNib is called when the nib file associated with a class is loaded from disk. Any class that can own a nib can use it. viewDidLoad is used only by view controllers. It is usually called when loading from nib as well but it can also be called by a view created in memory (very rare circumstance.)
In either case, you only put functionality in either that you only want to run once when the instance is first loaded. E.g. a common nubie mistake is to put code in viewDidLoad that needs to run every time the view appears. Say as with master view that opens a detail view and then reappears when the detail view is dismissed. If the code for the master view is in viewDidLoad it will only run the first time the master view is loaded but not any of the subsequent times the master view disappears and reappears.
You generally don't initialize any other views or do much of anything in the app delegate's awake from nib. That is usually performed in applicationDidFinishLaunching.

Should my app use just one managed object context?

Is it appropriate for my app to have several managed object contexts? I was going this route, (passing along my MOC from one instance of a UIViewController subclass to the next,) but I'm starting to run into EXC_BAD_ACCESS errors and I'm wondering if it could be related.
So, when do I want to use multiple ManagedObjectContexts, and (when) should I only use one?
Edit:
In my UISplitViewController based app, when deleting a row on my Master view, only after presenting a second view inside the main detail view, my detail view controller crashes on respondsToSelector, which I don't call ever.
Edit 2:
Basically, I have a master view and a detail view. In the detail view, the user presses a button. The button brings up a "new transaction" view. Instead of presenting the view modally, I manually add it to the detail view. If the user makes a change to the managed object context in this new view and then tries to delete the row in the master view, it causes a crash. If I present the same view modally, everything works just fine.
Furthermore, NSZombieEnabled says that a respondsToSelector method is being called on the (parent) detail view. I don't call that anywhere in my app. Could this be a memory issue? A threading issue? I don't explicitly create any new threads, but I don't know if there are any threads being created behind the scenes.
What might be the problem?
EDIT3:
This problem seems to get better. In my detail view, I also have a table, which, like the master view, uses an NSFetchedResults controller. When I delete the cell, I also hide the detail view, which causes it to be released. Releasing the detail view causes the app to crash. If I don't delete the detail view, the transactions in the detail view's table are deleted. (This is because I have Core Data set to cascade when an account is deleted.)
So, perhaps I have too many NSFetchResultsController objects? I believe that what is happening is follows:
When I delete a row, the NSFetchResultsController value changes and so it tries to fire the delegate method. However, the detail view has been removed and it's view controller deallocated. So, the delegate system fires a controllerDidChange method and crashes when trying to deliver the notification to the detail view.
How can I fix this?
Generally speaking you should use just one, unless you need to access data from multiple threads, in which case you'll need one per thread.
You certainly shouldn't need to create one per UIViewController.
You might also want to re-think whether you should pass the whole managed object context to a UIViewController anyway - how about just passing it the model objects it needs to do it's job?

What's the difference between the RootViewController, AppDelegate and the View Controller classes that I may create?

I am trying to learn programming for the iPhone and I keep seeing these files and I am not sure when is each file and content of those files referred to in the execution of a program built for the iPhone. I am trying to follow tutorials and tips available online but nowhere is there a point by point comparison or something like that. It would be great if any of you could list a few basic differences like when is each file referred and what should ideally go into each file and so on. Thanks for your time already.
In general, delegates can be thought of as event handlers. Accordingly, the AppDelegate is the main event handler for your entire application. It is told when the application has launched, when it will exit, when a Push notification comes in, when the app has gone into the background, etc. One of those events - applicationDidFinishLaunching - is typically responsible for creating the application's window and adding views to that window.
In most applications, the view that is added to the window is actually controlled by a UIViewController. Each UIViewController is responsible for managing the appearance of one main view plus all of its subviews. For example, a UITableViewController is responsible for managing a UITableView (main view) and all of the UITableViewCells (subview) that are inserted into that UITableView. The UIViewController typically acts as a delegate (event handler) to the views it is responsible for. When a user taps a table view cell, a method in the UITableViewController is called. When the user swipes to delete a separate method is called.
A generic UIViewController provides the same basic functionality, but for custom views. For example, the UIViewController may be responsible for displaying a few text views and a button. The UIViewController would create its main view, the text views and the button view. The text views and button view would be added to the view controller's main view as subviews. The UIViewController would register itself as the delegate for events from the text view (for example learning when the user has finished editing the text in the text view). It would also register a method to handle a button press originating from the button it owned. When any of these registered events occur, methods on the UIViewController are called allowing you to take whatever action is needed.
The rootViewController is a specific type of view controller used with navigation controllers. If you want an application that has the typical iOS navigation view hierarchy, your AppDelegate would typically add a UINavigationController to the app's window. That UINavigationController is useless without actually having content to display. That is where the rootViewController comes into play. You are responsible for providing a view controller (such as the one described above) to act as the first view stored in the UINavigationController's stack of views. This view will be displayed when the app starts up and anytime that the user pops subsequent ViewControllers off of the UINavigationController's stack.
Long winded I realize - but hope it helps.

Resources