Don't update Firebase data after first load - ios

I'm using firebase to store data from my iOS app. This data stored to my database are also readable from the app. There is view controller (B) which stores data with a button and a view controller (A) which show that data. I want either to kill the view controller (A) when i'm on (B) and the opposite or update (A) at the startup one time (as it does) and after that never update again. I want to do that because I have error sending data from (B) to my database. Sorry for my English.
Error :) : popViewControllerAnimated: called on while an existing transition or presentation is occurring; the navigation stack will not be updated.

Related

Where should I load data in from a firebase in a UIViewController

I'm having trouble trying to figure out where I should load in the data from Firebase into my app. I'm not sure where to load the data into viewDidLoad or viewWillAppear. I am currently loading data in viewDidLoad but when I visit another view controller that add items to Firebase to be displayed by the previous view controller. But when I pop back to the original view controller it doesn't show an update in the view controller that supposed to show the item that were updated or added to the database.
The best choice for your case is viewWillAppear as it's being called when you pop back , so make sure to free the array and load it again if it's not a child add observation
viewDidLoad() is only called once after the controller is loaded into memory (more info here: https://developer.apple.com/documentation/uikit/uiviewcontroller/1621495-viewdidload).
If you want to update your data when you go back to your controller, you should do it in viewWillAppear() or viewDidAppear(). The later is called after the former so it's your choice where to call the update function.
In addition, you can also update immediately when there is new data by using NotificationCenter, without the need to go back to your controller.

Refresh "root" data inside a UINavigationController and update data in navigation stack

I'm using storyboard with a UINavigationController that has view controllers A, B and C.
A is the root view controller of the navigation controller which at startup fetches some data. If I click on a row in A that will segue to B view controller with that data. Clicking on a row in B will segue to C view controller.
Later in my app for instance I'm inside C and the user wants to refresh the data. Meaning I need to fetch the root data for A view controller again.
How do I rebuild my navigation hierarchy again after the user have refreshed the data? I need to update the data source in A and then in B and then finally in C somehow.
It's merely a matter of planning ahead, isn't it? It's your program so it's your job to provide yourself with the facilities that you will need. In this situation there is no need to "rebuild" anything (though you could do that, I suppose). A and B both do still exist even while you're showing C, so all you have to do is communicate with them as needed. If the data-fetching power resides only in A, then simply provide A with a method that C can call in order to request the refresh and receive the updated data. If A and B are subsequently shown again (because the user pops back from C), they will of course use their viewWillAppear to update their respective interfaces as well. But at the moment A and B are merely objects, and communicating between objects is, after all, what object-oriented programming is all about.
You should put all the logic of A in another objet which could be accessible from A and C.
I think this post is a good place to start

iOS: managing state between segues

I'm working on an iPad app that has two controllers, a Login Controller and a View Controller. The Login Controller challenges the user for a username/password and once authenticated, there's a modal segue to the View Controller.
I've implemented a timeout wherein after 20 minutes of inactivity, the app segues back to the Login Controller. However, when the user logs back into the app, the state of the View Controller isn't preserved.
Is there a way to pass the View Controller object back to the Login Controller for re-use after logging into the app again? Is there a better way to manage the state?
Two possibilities come to mind...
You can create a model object either as a "singleton" or possibly owned by the application delegate and update it from the view controller and read from it whenever your view controller's view will appear.
The other option would be to have the view controller as the app's root controller and the login controller a modal overlay.
Your comment "Manage the state" is the answer you seek.
If there are changeable things about your view controller you'd like to save, then save them as they change, (either in NSUserDefaults, or CoreData, or some other persistent store) and have them populate when ViewController calls viewDidLoad.
Storing an entire UIViewController at the AppDelegate level just to preserve a handful of values is likely to be very wasteful, and won't help you at all if the app terminates. For this and many other reasons, your best bet is to follow MVC and make your model a persistent store which feeds the view.

How do I push a VC from a push notification?

I receive a push which has an id of an object I need to look up. I save this to the app delegate.
In my main view controller, I fetch an index of all the objects.
I check if my app delegate has an id saved. If it does, I scan the objects I fetched from the index and push a detail view controller with that object.
The new view controller doesn't function properly and crashes when I tap back. Research indicated this is because my VC had a nil frame.
What's a good workflow for pushing a detail VC from a push?
With the information you have provided seems to be there is something wrong with your design.
Normally your user has a flow in navigation controller (1-2-3-4-5) and reaches to a point.
What you might be trying to do is (1-5) and when the user comes back it crashes because it haven't been able to create that state back. If this is the case there is something wrong with your design.
You can't push 5th element directly to a stack (a nav controller is a stack) without pushing first four. Reuse the code, trace the path normally user follows to create that state back.

Pattern for preloading data for subsequent view to be displayed

Very simple use case: Let's say an iOS app displays a MovieListController view (inside of a UINavigationController) with a list of movies. When the user touches on one, the app pushes a MovieDetailController onto the navigation stack (i.e. [[MovieDetailController alloc] initWithMovieId:(NSString *). In the MovieDetailController's viewDidAppear: method, it makes an HTTP call to retrieve details based on the movie ID passed into it.
The challenge is that the MovieDetailController gets pushed onto the navigation stack right away, and for a second or two while the details haven't been retrieved, the view shows a bunch of blank fields, which is undesirable.
To get around this, I'm thinking of having the MovieListController not push the MovieDetailController onto the stack right away. Instead, it would put up a progress indicator (I'm using SVProgressHUD), then call MovieDetailController's initWithMovieId: method which would kick off the HTTP call. Then when the data is received, the MovieDetailController would make a callback back to MovieListController to remove the progress indicator and then push the MovieDetailController onto the navigation stack.
Is there a better pattern for this type of scenario? Should I be considering having the MovieDetailController push itself onto the navigation stack when it's ready?
Note: I have considered loading the detail view and putting up an activity indicator, but you'll still be able to see an 'empty view' behind it which looks a bit weird. I have also considered just having the MovieListController retrieve the details itself but this seems to break the encapsulation model - the MovieListController should just be concerned about listing movies, not about their details.
Any thoughts? This Movie stuff is just an example - looking for a general pattern here.
Personally I would take the following approach.
User selects the movie they want details for
Push to the detail view and rather than showing your skeleton view with empty fields, overlay a loading view, you could continue using your progress HUD on top of this for any animations you gain with that.
Once the results come down, remove your HUD and the loading overlay view that is hiding all the data/fields
The reason I would go this route rather than showing the HUD before pushing the view controller is that you can give the user the opportunity to cancel their selection. I am not familiar with SVProgressHUD but hopefully when a HUD is displayed you can enable touches, specifically the user touching Back on your UINavigationController in the event they accidentally selected the movie or the request is just taking longer than they are willing to wait for.
It also separates the logic form your list view, your detail view is standalone and could be initialized anywhere in your app (maybe you want to cross link similar movies within a movie detail view) and you do not need to rewrite the logic of the presenting view waiting on the results to come back.
In this situation, I personally would return to the model-view-controller pattern.
There are several system apps that display a detail view from a list of objects, e.g. Calendar, Contacts, etc. Presumably, as with EKEvent and ABPerson in their respective apps, the main view controller maintains a list of the model objects. When the user selects one of the items, the main view controller passes the selected model object to the detail view controller. The detail view controller itself doesn't have to do any data loading. So, like #ChrisWagner said, we want to separate the logic from the view controller.
Method
Similarly, you might want to use a MovieList class that stores an array of Movie objects. Each Movie stores the values for all the fields in the detail view controller - essentially, all the information the app needs about the movie. For example, you might have a property NSString *movieTitle, or NSDate *premiereDate. The movieTitle would be set by the MovieList at initialization because it's just metadata; on the other hand, the premiereDate might be nil if the data hasn't loaded, so you would have a property BOOL isLoaded to check for this condition.
You could then proceed in one of two ways:
1) Say the main view controller wants to push a detail view controller for a movie. Then the main view controller would dig the appropriate Movie out of the MovieList and check if it's loaded. If not, it would call something like -(void)loadContents on the Movie. When the model object is finished loading, it will post a notification that it's finished loading. At this point the main view controller will dismiss its progress view and push the detail view. If you use (1), it's not as important to use a MovieList coordinator.
2) If you want to be more aggressive about loading the movie information, you could implement a method on MovieList that calls loadContents on its Movies in the background. Then there's a higher chance that a movie will already be loaded when the user selects it.
Edit: Note that if you decide to use a MovieList type object, only the main view controller should be allowed to access this list. In a way, the model structure I've described parallels the view controller structure. The detail view controller doesn't know about the list view controller, so it shouldn't know about the MovieList either.
Benefit
The benefit of using this Movie and MovieList structure is that the data model is completely separated from the view controllers. That way, the user is free to cancel, select, present and dismiss view controllers while the data is loading. (Imagine if the user pressed Back to dismiss the progress HUD, canceling any HTTP data it would have gathered. Then, if he decides to come back to that same movie, the new detail view controller has to start loading afresh.) Also, if you decide to replace view controller classes in the development process, you won't have to copy and paste a bunch of data-handling code.
I think you'll find that structuring your app in this way not only gives you and the user more freedom, it also makes your app efficient and open to later extensions. (Sorry to post so late, but I wanted to include MVC in this pattern-related discussion!)
I think a more advanced route would be to start the detail requests as the cells are being being shown on in the tableview/collection view. Then as the cells move offscreen, cancel the requests. You might be loading movie details unnecessarily, but I don't think this is a big deal, because you'd only be filling your db with movie details you might not need and coredata can handle that. This is assuming that your api requests are happening on a bg thread and they don't affect the main(UI) thread.

Resources