In my project I'm using a UIPageControl as a container UIViewController for scrolling. I used this tutorial (using ARC and storyboards): http://www.wannabegeek.com/?p=168 and the source code: https://github.com/wannabegeek/PageViewController
As you can see there are 3 ViewControllers in the project, and they are added as child on the CustomPagerViewController. In that project there are only 3 ViewControllers that are added, but in my project I got more than 3 ViewControllers and I also reuse them with another text, image, label, etc. on it. The problem is that in the project all those ViewControllers are getting loaded whenever the CustomPagerViewController is loaded and this costs memory so I'm looking for another way how I can deal with this problem instead of loading them all at once?
You shouldn't try to optimise controller allocation in this way. Obviously retaining view controllers in memory takes up space, but believe me, not that much.
We have to difference here between the controller and its view. Views can take up a lot of memory in order to get themselves displayed on screen, but iOS already has its own mechanisms to free this memory when it's no longer required (ie: the view is not on screen / doesn't have a window).
iOS view controllers used to free views memory by themselves (this behaviour was in [UIViewControllers didReceiveMemoryWarning]), but that's no longer the case in iOS 6. Now you're responsible for doing so in you feel like it's needed by your app. Bear in mind that despite nilling these views in this method (or dealloc), you won't be saving much memory, as most part of the (graphical) resources used to display a view in screen may have already been released by iOS, and the amount of memory you may end up freeing close to 0.
To sum up, in your case I'd convert PagerViewController into a proper iOS container controller using this guide. The key is to call the following methods:
[UIViewController addChildViewController:]
[UIViewController willMoveToParentViewController]
[UIViewController removeFromParentViewController]
[UIView addSubview:]
[UIView removeFromSuperview]
in the right order according to your needs. In your case, you can add / remove these in the scrollViewDidScroll method. Use them in this way, and let Apple's magic happen.
You might as well use UIPageViewController which gives you some nice out-of-the-box features.
Related
In iOS6 the method viewDidUnload became deprecated, the memory management has changed a lot for a UIViewController. Here is a little brief about the new patterns.
The part that occupies more memory in a view controller is the view (and of course huge data that you would eventually create). The view itself it doesn't consume so much memory, is the backing store, the part that is drawn (for the most curious is the CABackingStore). This new pattern seems to check as volatile the memory occupied by all the backing stores owned by view controllers' views that are not displayed in a window. When a memory warning comes this backing store will be purged from memory. With this method you can save the process of recreating the view that is quite expensive.
Apple says that is safe to remove viewDidUnload/viewWillUnload from also iOS5 project and even if you set the deployment target to iOS5 the templates don't show those methods. I understand that if the outlets owned by the view are weak, when you release the view controller's view in the superclass implementation everything will be dealloc correctly without leaks or zombies thanks to ARC.
Since I really appreciate this new approach I'm not confident with this kind of situation: let's suppose that we have a view controller and its view, this view is just a content view that will host different views created in the view controller's xib, changing them at runtime dynamically. When you create outlets for this views they are automatically created as strong and that makes sense because the the "main view" doesn't own none o f them. Regarding the new rules the backing store of this views will not be signed as volatile since they are not owned by the main view in iOS6 and in iOS5 (if I remove the viewDidUnLoad) they will be not released for the same reason.How can i manage this situation? It will be correct to release them inside the didReceiveMemoryWarning? but were can I recreate them in iOS6 if the view will be loaded only once ?
I have a simple UIViewController whose view is created via a Nib. Here's the structure of the Nib:
And a screenshot of the layout:
Whatever the previous view (there are 2 possibilities), there is significant stutter/lag when transitioning to this view. Even the keyboard animation is lagged. Also, this is only on an actual device.
I've tried removing the MKMapView to see if that was the case, but it didn't make a difference.
Is the Nib too complex? Should I load everything via code? I'm not sure what it could be, but its really annoying, especially when the rest of the app is super crisp.
As far as code goes, its nothing special: just alloc/init a view, push it onto a UINavigationController, etc. Nothing in the viewWillAppear:/viewWillDisappear:.
Coming from Reddit, where you posted code (probably want to do that here too):
My guess would be the lag is coming from the section from line 44 through 80ish, where you build the overlay. Something in there might be taking longer than you think (Spotpoint unSerialize sounds fishy). You typically want to do as little work as possible in viewDidLoad, since that is called as the UI is transitioning to the new view controller.
Try throwing that code into a GCD queue or running it in the background, and see if that helps the loading stutter.
I have developed an application that uses UINavigationController to handle multiple instances of the same UIViewController, and it is working great. The UIViewControllers that I am using, however, are using a lot of images in a sometimes very big UITableView as loaded from the server, so I am beginning to be more conscience of performance and memory.
What happens to a UIViewController that isn't at the top of the stack? If I drill down through a few views, that all have images, whenever I return to the view, the UINavigationController presents the view without any loading, so I'm wondering if those views on the stack are in any way potentially hogging lots of valuable resources? Such as memory?
What is the best way to handle that situation? Is there anything I should know about that I apparently don't?
Thanks!
This is, actually, explained in the documentation for iOS. Check XCode>Organiser>Documentation>iOS, there is a nice drawing explaining how the UINavigationController stack works, that should be better than words.
However, in a nutshell, you have viewDidLoad and viewWillAppear (and their opposites) methods that serve to alleviate your fears. They should be used to create/delete any "memory hogging" parts of your code that you don't need "right now". However, as far as I know, you don't have control over what iOS will decide is necessary to flush or not, if it's controlled directly by UINavigationController.
I'm developing an app to browse online photos, and sometimes received memory warning(level 1), after that, if I go back to last UIViewController(in a NavigationControll), I found that some custom UIView lost, I cannot get them back, but I can create new such UIView
does anyone know the problem?
The memory warning prompts the os to dump any unneeded views. If you create them in IB, or in the viewDidLoad or loadView method in your view controller they'll be re-created when your view re-loads. You could also have your view controller retain them specifically, but that'll have a larger memory footprint than just re-creating them whenever they're needed.
I should say, loadView is only called if you don't use a nib for creating your view, so viewDidLoad is probably where you want to put them.
It's expected behavior. You can override didReceiveMemoryWarning (i.e. do nothing and don't call on super); but what you really want is to handle those situations correctly, i.e. set the views up again if necessary.
In a multi-view application, do you think its better to let views automatically get unloaded in memory tight situations, or to actually only ever have one View Controller allocated at a time, and when you switch views, the new one is created, the old one removed, the new one adde d and the old one released. Deallocating every time also means that there is a slight delay when switching to a new tab (very slight). So What do you think?
Also, I'm a bit confused about how and when and where and by who views are released (through viewDidUnload) automatically. If someone could clarify that for me, thanks.
In general, don't unload views unless you have to (didReceiveMemoryWarning) or it makes sense (something like a login form that's unlikely going to be used again).
You can't really assume that you have a fixed amount of memory. iPhone's have less memory than iPod touches. iPhone 3GS's have more memory than either. Jail-broken handsets often have substantially less memory.
By only releasing views when you have to you're making your app run faster on the 3GS and allowing it to run when there's less memory available.
The didReceiveMemoryWarning method releases the view if it is not visible. The following is from the documentation (v3.x):
The default implementation of this
method checks to see if the view
controller can safely release its
view. This is possible if the view
itself does not have a superview and
can be reloaded either from a nib file
or using a custom loadView method. If
the view can be released, this method
releases it and calls the
viewDidUnload method.
Obviously you also need to release any cached data. SDK2.x does not have the viewDidUnload method.
Depends, if you have a bunch of Views that the user switch back on forth from often then I would say to keep those in memory at that time, if theres views where the user wont come back to for awhile then you can probably unload that viewController and save memory. However if you have views that are taking up a ton of memory each then it might be wise to unload the viewcontroller when its not in use. Its really a matter of how often you are going back to the views and how much memory the view takes, also how many views you have. Taking these things into consideration you should be able to make a good decision of when to keep the viewControllers around and when the unload them. I believe that the view is a round as long as the ViewController is around (unless u release it explictly, which might have bad side effects (dont know)) , viewdidUnload just tells you that the view was unloaded of the screen, not too sure on that point tho.