I am new in iOS and I have tab bar. I have 4 tabs like Facebook.
In my case all data should be updated from server anytime when user goes one of that screen.
One guy said calling viewDidLoad frequently can make memory leaks. Is that true?
So what's the best play here? Every time call viewDidLoad() and load data from server or there is another way to handle this not calling viewDidLoad() every time.
There is no pull to refresh in that screens
viewDidLoad() will only be called the first time the view controller is loaded. Using a tab bar controller will usually keep the view controllers in memory as the user switches tabs so if you want the loading to occur every time the user goes to a new screen, this is not the best place for it.
I would suggest using viewWillAppear or viewDidAppear. If you're updating data from the network, make sure to do the loading on a background thread to ensure the interface does not get blocked (regardless of which method you use).
Personally I would put network loading code inside viewDidAppear as to me it makes more sense to call the network after the view has finished appearing since it will presumably not finish immediately. This way it is also easier to present a UI element that shows data is loading to the user.
Related
One of the tabs in my app presents blog posts. I notice that when I move to another tab or leave the app that when I return, new blog posts are not downloading. The download is kicked off by viewDidLoad() in the ViewController. It's not firing when I return to this view.
Why isn't viewDidLoad() firing when I leave the app? How long does the app remain view loaded in memory?
How should I check for new posts when the user comes back to the app or from another tab?
Thanks!
viewDidLoad may not be the best place to download the updates. If for example you push from ViewController A -> ViewController B, the first view controller (A) isn't unloaded.
You may want to put the code in viewDidAppear or viewWillAppear.
Look at ViewController LifeCycle for some reference.
You can use the applicationDidBecomeActive notification to trigger updates or whatever else you want your app to do when it is brought back from the background.
There is a good answer on this here: How can I use applicationDidBecomeActive in UIViewController?
There is also a good article on Apple's website about handling transitions from various app states here: https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/StrategiesforHandlingAppStateTransitions/StrategiesforHandlingAppStateTransitions.html
ViewDidLoad is only called once when the ViewController is instantiated. In a UITavBarController, the child view controllers are only instantiated once. As you move from tab to tab, the ViewControllers are kept in memory.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITabBarController_Class/
If you background the app, then iOS will keep it in memory until it starts to get low, then starts to terminate apps.
Take a look at the delegate for the TabBar
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITabBarControllerDelegate_Protocol/index.html
This can tell you specifically when the user switches tabs. But if they flip back and forth, it could needlessly create several API requests.
I have created a customise table cell in which i am downloading image in background thread in cell class and now suppose i moved to previous view controller. Would background thread still would execute and will crash the application. I could;t test this scenario as images loading fast and didn't get chance to move to previous view controller.
What would be the consequences?
Problems can certainly arise if you don't do this correctly. You probably won't get a crash, because the NSURLSession prevents that for you by retaining its delegate. But by the same token, the view controller you have left will leak; it won't go out of existence, and the downloads and other things will continue to happen.
If you are doing it correctly, all downloads should be cancelled by you when the view controller goes out of existence. If you don't need these downloads occupying bandwidth and CPU time, you have a duty to call invalidateAndCancel to make that happen. Note that you generally cannot do this in the view controller's deinit, exactly because of the retain cycle. But once you have done it, your view controller will be able to go out of existence in good order.
I am using uiwebview to show my web contents. Navigating to different url using RevealViewController. I am caching all the pages for the first time entry.
After visiting few pages when trying to goto rear view (reveal view controller menu screen), the app got stuck for some time on clicking of the menu button.
(Every time visiting and caching a page that will increase the memory size of the app)
If the presentation of the menu is slow, it is probably because you are doing some heavy processsing inside the initialiser of the menu or the viewDidLoad function, or the menu button pressed function.
My suggestion is to move any of that processing to the viewDidAppear method of your menu controller instead, so that the UI is not blocked by any processing you do. You could also use GCD to disaptch_async anything that is intensive.
If you give some code examples it will be easier to see exactly what the problem is, particularly the code that executes when the menu button is pressed.
I'm looking into the viewDidLoad and viewDidAppear methods to better understand what they both do and I came across an article which uses the example of a banking application to explain how these methods work:
Consider a banking application that shows your current balance. A user
can tap on a button, which presents a list of nearby ATMs in a modal
view controller. In order to get the list of nearby ATMs, the
application must make a core location and web service request.
In this situation, a programmer could get away with requesting the
list of nearby ATMs from the server in viewDidLoad. The view
controller is only presented once, both viewDidLoad and
viewWillAppear: will be called back to back and only once for that
particular view controller instance. The net effect of the code in
either of these two methods will be the same.
But this is a bad idea. Consider what would happen if you wanted to
move the ATM view controller into a tab bar controller. Now, the ATM
view controller – with its ATM fetching code in viewDidLoad only
fetches the list of ATMs once. So you are in Atlanta on Tuesday, open
up your application to look for an ATM, then check your balance. Then
you travel to New York on Wednesday, re-open the banking application,
and you only see ATMs in Atlanta. The view was already loaded, no need
to call viewDidLoad and now you’re looking at stale data.
Sadly, I still don't fully understand how/why both viewDidLoad and viewWillAppear will be called 'back to back', or what adding the ATM view controller to a tab bar controller means in terms of these methods.
viewDidLoad method will call only once a life time of viewController and that is when viewController object will first load in memory.
where as viewWillAppear method will call every time when a view will appear to screen or you can say will be topViewController...
Explanation:
Consider you have tab based app with two tabs. Tab1 associated with viewController1 and tab2 is associated with viewController2. Now when you will run your app and you will see tab one is selected and viewController1 is on view and you want to change to tab2, when you will tap on tab2 then tabVieController2's object will create and load to memory first time hence its viewDidLoad method will call, and soon after that it will appear to window and viewWillAppear will also get call.
Now if you you try changing tabs by click on them only viewWillAppear methods will get called for both, as they are in memory already.
It simple, viewDidLoad get called when the view is load in, either via NIB, storyboard or with the loadView method. The viewWillAppear: is called when the view is presented.
When a view is added to a tab bar it only gets load once, thus the viewDidLoad will only be called once. But if the user switch to an other tab and back to the same view the viewDidLoad will not be called. This is because the view is already loaded.
However the viewWillAppear: is called in both cases just before the view is shown. Thus this will be called when the user first opens the tab and when it switches back to that tab.
I think they are referring to the fact that the view is loaded every time the modal view controller appears (thus the data is constantly refreshed) but only once when it is part of tab bar (only loaded on app launch). Kind of a whacky example to explain the methods though.
You might want to read up on the view controller lifecycle to know when to implement what in which method:
Responding to Display-Related Notifications
View Loading and Unloading
I am building application that uses tab bar.
I have say A & B tab.
When I click on tab A, then it takes time for loading data from server.
Similarly, when I click on tab B, it takes time loading.
If click on tab A and wait until it loads all data, and then move to tab B, it works fine.
If I click on tab A and move to tab B while A was still loading data from server, it crashes the app.
I tried to unload the view at view did unload method. But, it did not work.
Can anyone suggest me how to solve this problem?
in each view loaded by tab bar controller, I added self.view = nil; for each view will disappear method. This solved by problem. May be this will be helpful.
Without seeing your code, it's difficult to answer. There could be many possible causes. However, my first guess would be that you're dispatching your NSURLConnection completion handler to the main queue and trying to update the UI, which is no longer in sync.
In other words, you start on tab A and the download commences asynchronously. You then switch to tab B in your UI, starting the second download on another queue. Your tab A download completes, and the completion handler is then dispatched to the main queue. In that completion handler, you may have code to, for example, reload a UITableView on tab A. But since you are no longer on tab A, that view controller (and all of its associated views) do not currently exist in your program's life cycle. If you're not properly checking for nil responses, etc., this could create a crash.
Another less likely possibility is you are running out of memory. Easy to test for this: simply monitor the memory usage as you navigate through the app. Your app may crash if it doesn't properly respond to a memory warning. This would be possible if you were using an NSURLCache, perhaps, and committing too much memory to both download requests simultaneously.