I'm short on RAM most of the time.
Perhaps you should rethink your app logic if you are piling up views like that. However have you tried setting the bottom views hidden property to YES?
If its not visible, remove it from the superview, if you are so tight on RAM.
However, I can't see why you are in a state with multiple seemingly-memory-heavy stacked views in the first place.
Related
I've been doing iOS for a while now, but when it comes to dynamically hiding / showing elements, I'm a bit lost.
Coming from Android, I'm used to being able to simply set views to visibility gone, but this doesn't exist on iOS.
So let's say I have the following scenario:
Basically I want to have a table, but the table should not fill the entire view controller. Instead it should leave place for optionally either a button, a multiline label, or possibly both at the bottom (if visible, these should be fixed, not scroll).
One way to solve this would be to use auto layout and modify constraints, like adding a zero height constraint. But that would make iOS kill one of the other constraints, which would make it hard to change it again. For the label, I wouldn't always want to have a height constraint, because it could be multiline, and should take the size it needs.
Maybe it's easier to skip autolayout here and modify frames instead, I don't know.
My question is: What approach would be best here?
Is there some other way of doing this I haven't thought of, or do I have to try to do what I described above?
I'm not primarily looking for code (code can be ok), but I'm more interested in a description of how it can be done.
I'd like to support iOS 7.
This problem had a variety of solutions, and opinion based, but I'm facing such questions a lot, when I don't know what to choose and what would be the "right thing".
So, I my opinion, the best solution here is using autolayout, you need to set height of label manually, but you have a few methods for this, at least you can play with it and if you don't succeed ask question about it. Using frames, you'll face same problem of calculating height, right? But with auto layout, you only need to set height, vertical space to 0, when you need to hide message.
You can also use constrains with priority lower 1000, and remove completely constraints from message (button, label) if you don't need it at all anymore.
For example, taking your layout image, you can make UIView with subviews: button, label. Top constraint connect to the UITableView, other constraints to the sides.Label and button will calculate the view's height. The only question here is label height.
So in ios assuming that the background of both these objects is opaque only the front most view in the Heirarchy will be visible and interactable, An easy solution would be to change the different frames of these two things you need and make sure they are in the back of your view heirachy, and when you need them to appear use view.bringSubviewToFront(mySubview) and view.pushSubviewToBack(mySubview) to make it disappear again. View obviously would be referring to main view of your view controller.
I have issue with autolayout.
I have three different views (could be n views as well). When I pin first one to top of super view and connect one next to the other everything seems fine. But if I want to change height of first one the other two does not follow (they stay on the same position). What I find weird about this is that if I connect only two views this works perfectly.
To have better understanding what I am trying to achieve I made simple, example solution with three views:
http://i.stack.imgur.com/cMwiB.png
So, when I set height of green view to 0 ( can be any other number as well ) and only red view is connected, this works fine, red will move as it should. Blue one is not connected and it remains where it is:
Here is screenshot when I connect blue to red:
What I tried to do:
connect blue one to green as well ( not working)
connect blue only to green ( not working )
"boxing": have boxes with views at the time ( ugly, hard to manage, not working in all cases)
What I would like to know:
what makes this happen? Can I change this kind of behavior?
What is the best practice to have flexible length for height (Besides UITableView)
Thanks in advance.
Ok, I think you're falling into the same trap I did, when I investigated autolayout some time ago. It's tricky to explain, but I'll do my best. When you work with autolayouts, you need to forget completely about setting a view's frame at all. And that, my friend, includes changing size and positioning. When you use autolayout, you define some constraints, some "rules", that the view tries to respect when rendering the screen, so the more specific the rules are, the less random will be the behavior of the view. I mean, if you just define the spacing between views, you're implying that the height of the views doesn't matter, so it's possible that some views grow or shrink when the re-layout is called (that is, if you don't specify a constraint for size. You probably want to always specify the size of some views in every layout...)
By the way, you're allowed to violate the constraints by manually changing the frame of an element AFTER a re-layout is called, but when the re-layout method is called again, the constraints will be forced so the size and positioning of the views will change. Quick tip: an easy way to force the re-layout method is to change orientation (command+left / command+right in the simulator).
So after saying that, I have to say that the layout you provided is completely working as intended, at least to me. When you change orientations the constraints you specified are ALWAYS being respected. If you want, you can try to apply some frame-setting in the viewDidAppear method, because this one is called AFTER the autolayout (and thus, you're able to violate the constraints temporally). After doing this, your view will be broken but once you change orientation the constraints should be respected again. Make sure it's that way.
From here I can only wish you luck ;) Oh, and refer to the documentation, it was a life saver to me when I looked at this half a year ago. https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/Introduction/Introduction.html It might seem a classic, but it's a pretty nice doc.
EDIT: one last thing. I have the impression that constraints are not designed to be dynamic. You define them once, and they're there always. Their main purpose is to ensure that subviews are rendered as intended in every screen resolution without fail, so if I were to make an application with moving views, I would leave them outside of the autolayout, or avoid using it at all. Just a personal impression though :)
This question is really basic. What is the performance difference between removing a UIView from the view hierarchy and hiding a UIView?
I have read that Views that are not needed should be removed from the view hierarchy. I currently have the situation that a UIButton should sometimes be visible. When do I hide the UIButton and when do I remove it from it's superview?
Is it expensive to change the view hierarchy?
I've done an experiment on iOS6 iPad mini, with a large scroll view that has a lot of rich content (including images, drop shadows, gradient layers, patterned background images, you know, those designers:) ) and I found that view.hidden=YES ≠ [view removeFromSuperview].
I originally thought that setting hidden to YES will make the view not being render/drawn, therefore having a lot of hidden views will have no impact on efficiency. But the actual result is:
1) if I set the offscreen views in the big scroll view to hidden (and unhide them when they come back into visible area), the scrolling is not smooth/continuous at all. When it's naturally decelerating it looks very jumpy.
2) if I remove the offscreen views from the scroll view (but still keep in memory with a tracking array, so when they come back in they can be added immediately), the scrolling is obviously smoother.
If you need to alternate between showing and hiding the subview, the best approach is definitely hiding it. For a UIButton the memory implications are not that great anyway. And the code is certainly simpler if you just switch the hidden property.
Also, you get the additional advantage that the hidden property is animatable!
Some years have passed between the initial question and the (rightfully) accepted answer. Let me add another factor: In the meantime, Apple has introduced AutoLayout, which — as some say — might come with quite a performance penalty in certain (deep) subview hierarchies.
If you are using AutoLayout, a view that is hidden will still get layouted, as opposed to the removed view (with its reference saved somewhere). Depending on your scenario, this could then make a performance difference.
I find myself often having to reposition subviews of a view after hiding or showing one of them. The way I'm doing this is by programmatically changing a view frame's origin and/or size, or its center. But is there an easier way I'm missing? Is there a way to do it with Autosizing masks?
I don't think there's any automatic way of doing this. You could probably get clever about how you do it programmatically (e.g. if you used a set of sequential tag identifiers, you could loop through and calculate the height of the previously visible tag to calculate the origin of the next subview; or if there are a group of subviews that are always going to move together, you could put them in a container UIView and thus move a whole bunch of them by just moving their container view; etc. ... it depends upon how they're laid out and which fields might be hidden).
This won't help you for now, but check out WWDC 2012 session 202 for a discussion of a relevant improvement in iOS 6.
I would like to make two UIViews. One of them will be fixed in the background with less opacity and the other above will be scrollable. Can I do this?
Yes you can do that. Its quite simple to do that implementation. You create 2 UIView's in the NIB file, one above the other ( in an hierarchy point of view). YOu can set the opacity of the one above, so you can see the one behind. Then, just drop an UIScrollView in the front one. If you need more help with specifics just reply. :)