I'm used to setting up views in StoryBoard and set inactivated views as Hidden, but I also don't want them to take up too much unnecessary memory. How to release a UIView when it is hidden or inactive?
By the way I'm programming in Swift. Thanks in advance.
I am agreed with The Paramagnetic Croissant. But if you want to remove it then you can use:
YourView.removeFromSuperview()
If you want to inactivate the views forever, you need to remove them from their superviews (view.removeFromSuperview() will do the job for you here). Otherwise it wouldn't make much sense to release it from memory since you'll have to reinstantiate the same view later on again which in my opinion is unnecessary overhead compared to just hiding and unhiding it.
Related
I want to practice creating simple apps using no storyboard. I am able to do the constraints programmatically (slowly) but I want to also practice separating my code into MVC. Is there a particular place/method that I am supposed to write the programatic constraints? Or does it not matter?
Good discussion in the comments. My thoughts, based on that discussion?
With an understanding that the question is subjective, you place your constraints:
The earliest in a view controller's life cycle where they work.
As "close" to the view as possible.
If it's something common, make it as universal as possible.
Understand how your specifics fit into everything.
(Understand, the question isn't limited to constraints. It could apply to hierarchies, UI, even database tables when you get down to it!)
Sticking to constraints, and my answer....
(1) Use the UIViewController and UIView lifecycles.
Generally the view life cycle is loadView, viewDidLoad, viewWillAppear, viewWillLayoutSubviews, viewDidLayoutSubviews, and viewDidAppear. great SO answer detailing this.
I believe that loadView is too early for constraints, but not viewDidLoad - **provided you aren't expecting to know the frame size. While many say viewDidLayoutSubviews is the right place for that, I've found that viewWillLayoutSubviews most times works just as well. Either way, get your constraints set as soon as possible!
(2) Do it as close to the view as possible.
If you have subviews - I have a "ToolBar" class of objects - you want the constraints, at least as much as possible, to be coded inside the class. For instance, in my tool bar, it slides out, has buttons, and even rotates upon orientation. The only constraints not inside these classes is for orientation - that owner is (and I believe should be) the view controller instantiating it.
(3) Make it universal.
I plan to use this tool bar across a few apps. So the first thing I did was add it to a framework. This framework was needed because I had an app that I delivered a photo editing exension - and the "edit" screen is as much the same as possible. In the end I move all my constraints there. (At least as much as possible.) Anything that I believe is reusable.
(4) Understand the specific requirements of your app.
This should be obvious. If you need to code for various orientations, use arrays and activate/deactivate them. (YES, a common mistake is replacing them! That's setting yourself up for some major headaches.)
If you can keep things active, declare the constraint, set `isActive = true1, and forget about it. If you need to adjust that constraint's constant or multiplier, in the declaration name it and then where you need to alter it, do it.
My conclusion? Auto layout is a very useful tool - more so in code. But the placement of code is like asking "how does one code an OOP app for auto rentals" or " how does one design a database for auto rentals". It not just an art, there are many answers. These are the "rules" I try to follow - YMMV.
To get started with this style of development I recommend checking out Let's Build That App as he goes through very in-depth examples of setting up complex apps entirely in code, without storyboards.
The way he structures the constraints is using a custom implementation of UIView, that way your view code is separated from the ViewController. Then, in the viewDidLoad method you can instantiate your implementation of UIView with something like self.view = MyView().
I wrote a few apps like this. The major drawbacks are that it can become very difficult to make quick adjustments, and you really need to learn about all the different types of constraints you can use.
Here's a pastebin of some extensions I used when doing this. I hope this helps.
I guess i might not understand how memory deallocates in Swift properly and thats why i wanted to ask this:
If i create a Message to the user using a UIView with a Label. i show it with an animation and then use ".removeFromSuperview()". when does it's memory deallocates? what are the conditions for it to deallocate?
Im asking because if it doesn't deallocate until the app closes - it means that for the run of the app - each message shown and then hidden will take up memory for no good reason.
Thanks for anyone who explains :)
Views maintain a strong reference to their subviews. Once the subview is removed, the superview relinquishes this reference. If you have no other strong references the retain count will decrement to zero and the view will be released.
So I do understand, that I should release the objects that I own. (alloc/copy/retain stuff)
And I also do understand(kinda?), that if I had #property with retain in some of my class, or some instance variable with alloc/init, then I should write a custom dealloc to make sure those ones gets deallocated with that class.
What I do not understand is should I manually release the cell objects for example? (since I am creating it in cellForRowAtIndexPath with alloc/init? Yea, I know, that tableView should kill those cells when it gets deallocated, but do I want to make sure?
Also, could I manually release UILabel, UITextField and so on? I do know that those are gets killed when you deallocate the view, but again, still, do I want to make sure?
UPDATE:
Yea, thanks for the tip about reference counting, but the project exact purpose is to do some simple stuff, using manual memory management.
It is funny how most of the tutors nowadays skips this part entirely so the novice like myself have to figure all that stuff by themselves.
Objective C supports Automatic Reference Counting which does almost all memory management for you. I suggest you migrate your old code to ARC; this is quite easy (Xcode has refactoring support for this) and it will save you a lot of hassle.
Unless you have a strong/retain pointer to a UI element they will be automatically dealloced once they go out of the screen.
Regarding the cells - you should never dealloc them because they're intended to be reused. If you dealloc and re-init them you'll get a REALLY bad performance while scrolling.
Also, as Glorfindel said, consider using ARC (if you're not using already) and your life will be much easier.
Since I converted an old app to iOS 6 I've started getting the following message in my console.
WARNING: Slow defaults access for key ClientState took 0.023656 seconds, tolerance is 0.020000
Other than updating my code from iOS 5 to iOS 6, I also switched over to auto-layout. I've run Instruments/Time Profiler and the rootViewController in my appDelegate is the problem. Everytime I switch view controllers it sucks the vast major of the time, (regardless of whether I have to instantiate the view controller or re-using one which already exists).
window.rootViewController = myViewController;
I know what the method does superficially, but I'm not sure what happens under the covers... what would cause it to be slow now and what can I do to speed it up?
EDIT: I've tried taking my storyboard off auto-layout and the problem vanishes (of course my UI layout is in shambles). So the obvious conclusion is, it's something about auto-layout. I've probably just under 70 views all combined on the screen and the various constraints needed to lay them out. I have a hard time believing auto-layout is that much slower (from ~80ms with auto-layout turned off to ~1370ms with auto- layout turned on).
Having 70 views on-screen sounds like a lot! My proposal is to make it simpler in some way:
Do you REALLY need all 70 views at the same time?
Check if all views need autolayout, remove it where-ever possible
Can some views be replaced by graphics? I've used views e.g. for shadows, might have been images
Can you split storyBoard into several smaller ones e.g. one for login, details, edit mode etc. Part of the slowness might come from system having to deal with (too) big storyBoards.
Consider creating a new project with 2 view controllers and test the switching speed. Every iOS app has a window, a root view controller and a view controller. The problem isn't likely to be as narrow and clear-cut as you may be hoping. What does each view controller load? Did you inspect the underlying code? Does app delegate do anything on initialization or change of root view controller?
Does UIImageView automatically release image resources when it isn't in view? And perhaps when the app gets a memory warning?
If not, I'm considering writing a subclass (e.g. SmartReleaseImageView) that does so, to be used in particular situations where this would be beneficial. I was thinking of behaviour along these lines:
When SmartReleaseImageView receives setImage message, it registers itself with a manager e.g. SmartReleaseImageViewManager.
When app gets a memory warning, SmartReleaseImageViewManager loops through all its SmartReleaseImageViews and checks whether any of them aren't added to a superview, or checks whether any of them have a frame that is culled due to being outside of the bounds of the main window.
When SmartReleaseImageView detects that it has come into view and has been released, it loads the image again. So perhaps, it would need to have a method like setImageURL rather than setImage in the first place.
Is this kind of behaviour already built into UIImageView? Or does it exist in a 3rd party version anywhere? Or is there a problem with idea?
(I'm writing a UIImageView-heavy app, and it would be nice to have a global catch-all solution that would help with the memory situation, rather than adding lots of extra code to my UIViewControllers.)
EDIT: Answers so far suggest that UIViewController should be responsible. This is true, and I guess my particular case is atypical. In my case, the UIViewController can contain a lot of custom views (with their own hierarchy) that it doesn't necessarily know the structure of, and which go in and out of view frequently. So, it's difficult for it to know when to release its resources. But yes, perhaps I should find a way for it to deal with the problem itself...
Well, you actually have this automatic management implemented in the UIViewController. Since UIImageView is a subclass of UIView, your view controller should be able to manage it automatically.
Memory Management
Memory is a critical resource in iOS, and view controllers provide
built-in support for reducing their memory footprint at critical
times. The UIViewController class provides some automatic handling of
low-memory conditions through its didReceiveMemoryWarning method,
which releases unneeded memory. Prior to iOS 3.0, this method was the
only way to release additional memory associated with your custom view
controller class but in iOS 3.0 and later, the viewDidUnload method
may be a more appropriate place for most needs.
When a low-memory warning occurs, the UIViewController class purges
its views if it knows it can reload or recreate them again later. If
this happens, it also calls the viewDidUnload method to give your code
a chance to relinquish ownership of any objects that are associated
with your view hierarchy, including objects loaded with the nib file,
objects created in your viewDidLoad method, and objects created lazily
at runtime and added to the view hierarchy. Typically, if your view
controller contains outlets (properties or raw variables that contain
the IBOutlet keyword), you should use the viewDidUnload method to
relinquish ownership of those outlets or any other view-related data
that you no longer need.
source: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
Short answer:
UIImageView does not release resources, never.
But all your views (including UIImageView) are released when the system needs more memory. Note that you have to release your views in [UIViewController viewDidUnload].
Edit:
Unfortunately, it doesn't work when the controller is not displayed. It that case I suggest to purge the components manually in viewDidDissappear (call viewDidUnload manually and remove components from the view hierarchy).
Anyway, this won't help if one view controller has too many images in its hierarchy. In this case I would recommend to create a set of UIImageViews and reuse them, in the same way as UITableView reuses its cells.