I have a view on a nib in Interface Builder. It's got a several UIStackViews within the nib, which I used because it's a easy to align UI elements. A colleague suggested I not use UIStackViews because they're "expensive" from a computational standpoint. The alternative is setting constraints for individual elements manually.
What Xcode tool can I use to validate my colleague's assertion and how would I use it? The best thing I've found is this, but I was hoping for something a little more granular. The nib in question is a UITableViewCell.
they're "expensive" from a computational standpoint
Okay, I will now attempt to demonstrate that that's utterly bogus.
A stack view is not magic. A stack view does not perform any special run-time adjustments. A stack view is just a constraint-maker, no more, no less. So are you. Everything a stack view does, you could do. And the stack view's resulting constraints are exactly the same constraints you would have created yourself (assuming you even know how). Therefore, the constraints themselves are not more expensive just because the stack view made them.
So let's talk about the initial generation of the constraints. Well, the stack view generates its constraints by rote. It's just a simple formulaic approach based on the parameters already given by such things as the stack view's settings and (in some cases) the intrinsic content sizes of the arranged subviews. So it takes effectively no time at all for the stack view to spit out the constraints that it generates, and it only has to do it once.
So if the generation of the constraints is not expensive, and if the constraints themselves are not expensive, where is the expense? It's nowhere.
Someone might argue that for a particular desired outcome using a stack view is unnecessarily complicated, or lazy, so it would have been "better" to make the constraints yourself; but "expensive" doesn't seem to me to be a genuine charge that can be laid against stack views.
In digging around, I found a repo called LayoutFrameworkBenchmark. I ran the benchmarks in iOS 12 on an iPhone 7+ simulator. I gathered the data and dumped it in a Google Sheet. It does indeed show UIStackView is pokey versus other layout methods.
I now see why there seem to be people in both camps, however in the real world, the human eye is unlikely to notice much of a difference unless it's a huge collection.
Related
I have a complicated storyboard that has ~20 controllers developed over several years which has been working great. However, with most recent versions of Xcode, each time I make any changes at all to anything in the Storyboard, Xcode goes through and removes ambiguous="YES" in all my controllers. Is there any way to stop Xcode from doing this?
It fully breaks my layouts. Yes, I'd love to go rewrite every controller to not have this issue, but in practical terms these layouts are battle-tested on every device and OS version and that isn't a high value rewrite for me.
sorry to hear you are running into issues with this. Could you provide more information about the storyboard or a view controller sample that is running into layout issues after the change in ambiguous=YES status?
Generally, ambiguity is caused when there are not enough constraints to specify a size or position. For something like an Image View, if an image is specified, then it will have an intrinsic size, and it will be enough to specify just positioning constraints. If ambiguous=YES is disappearing on a re-save, then could there be enough constraints to specify its position and determine its size? Deleting a positional constrain for the given view would put it back into “ambiguous”.
I know this might be too late to answer, but I run into the same issue and I wanted to let a guide to somebody else seeing the same issue in the future.
When a view frame position is ambiguous, the storyboard shows up a warning. Then some subviews include this ambiguous="YES" property in the storyboard file.
That means the view configurations for this Trait is not right. That doesn't mean that layout will not show properly when running the app since we might have Constraints that modify that frame positioning.
I don't know if this is showing up also for constraints ambiguity.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
Goal is a vertical layout matching the top/bottom of the screen view as in the sample image ...
I have NSConstraints between each item in the UIScrollView
However on a small device screen such as the 5S it is not showing the bottom buttons
(i.e. when the screen height is less than content height)
Is there a solution with fixed height of each UI element, or do I perhaps need to calculate every height dynamically so that without the UIScrollView it will fit in to smaller heights?
In short,
use a UIStackView
for this problem.
"or do I perhaps need to calculate every height dynamically so that..."
In fact that is precisely the purpose of a UIStackView
Learning to be an expert with autolayout and constraints is not easy. It is a delicate and artistic process.
For the challenge at hand, I would begin with one large stack view which fills the screen. The stack view itself will space everything nicely.
your stack view parameters would likely be:
(start with zero spacing)
and as you probably know use these to indeed test each device size:
Note that furthermore, in extreme situations, you will have to indeed also let certain of the elements shrink (it's your choice) when you run out of gaps to shrink. Unfortunately you must master all these techniques to make modern reactive apps.
Note, one key on this layout is that you have to let the spaces collapse as it gets smaller. Indeed the stack view will do precisely that for you with the correct settings.
That is a huge field of expertise, you would need to ask another question about it once you have
eliminated the scroll view
got the stack view working in a basic way
Indeed you will already find many QA about the issue on here.
Note that aBilal exactly described the situation in a comment:
"It is very simple, open your storyboard, select "iPhone SE" screen from View as at the bottom, rearrange all the screen accordingly using constrains. Now check your app will work on all screens including iPhone X as well. "
Indeed. it's much like saying:
"So you want to be Joe Walsh. It is very simple, purchase a guitar. Put one hand on each end. Now play. A lot.
:) It's a bit like that.
Adding scroll view for your screen doesn't seem to best solution according to me as it doesn't have so much elements on screen.
Best practice according to me is to always design the UI on smallest screen device your application is going to support and set your constraints accordingly. And I would suggest you to do the same into this situation as well. Hope this will be helpful.
Im having an issue with my layout in my story board. When i make a stack view how can i adjust the size of the UIlabel box to fit more text?
Image Example:
Also how can i get rid of the stack view to bring everything back to its original state?
To add more text- simply type more text. The label adjusts itself.
To get rid of the stack view- select the stack view and go to Editor->Unembed
I have given you a brief overview of auto layout. The examples that we have worked on were pretty easy. However, as your app UI becomes more complex, you will find it more difficult to define the layout constraints for all UI objects. Starting from iOS 9, Apple introduced a powerful feature called Stack Views that would make our developers' life a little bit simpler. You no longer need to define auto layout constraints for every UI objects. Stack views will take care of most of that.
In this chapter, we will continue to focus on discussing UI design with Interface Builder. I will teach you how to build a more comprehensive UI, which you may come across in a real-world application. You will learn how to:
Use stack views to lay out user interfaces.
Use image views to display images.
Manage images using the built-in asset catalog.
Adapt stack views using Size Classes.
On top of the above, we will explore more about auto layout. You'll be amazed how much you can get done without writing a line of code.
What is a Stack View
First things first, what is a stack view? The stack view provides a streamlined interface for laying out a collection of views in either a column or a row. In Keynote or Microsoft Powerpoint, you can group multiple objects together so that they can be moved or resized as a single object. Stack views offer a very similar feature. You can embed multiple UI objects into one by using stack views. In most cases, for views embedded in a stack view, you no longer need to define auto layout constraints.
Quick note: For views embedded in a stack view, they are usually known as arranged views.
The stack view manages the layout of its subviews and automatically applies layout constrants for you. That means, the subviews are ready to adapt to different screen sizes. Furthermore, you can embed a stack view in another stack view to build more complex user interfaces. Sounds cool, right?
Don’t get me wrong. It doesn’t mean you do not need to deal with auto layout. You still need to define the layout constrants for the stack views. It just saves you time from creating constraints for every UI element and makes it super easy to add/remove views from the layout.
So I recently was creating what Apple calls a leaf-level view (a button) and so I followed Apple's docs to implement -intrinsicContentSize and everything worked (albeit the code felt a bit weird - I had constraints set up in my -updateConstraints method to position subviews, as well as code in the -intrinsicContentSize method to calculate what the total size should be; it felt like I was giving duplicate information to the autolayout system).
However, I also ran into a post on here claiming to, instead of using -intrinsicContentSize, use rigid constraints and then the containerview will automatically resize to fit the views it contains. I also implemented this, and achieved the same result as above, but this time I didn't feel like I was duplicating information sent (I just sent the straight constraints). Note that I see the view as described in the post mentioned above as a so called leaf-level view since it doesn't sound like any other view would be added to it.
Which implementation of resizing a container view based on the content inside of it is the proper way to go?
I'm currently leaning towards the second method, due to the fact that I don't think I should be sending duplicate information, however Apple's documentation says otherwise (then again, Apple's docs can be a bit confusing/misleading at times).
Sidenote about my specific situation, f it matters: I have two subviews in my button, one being an image, the other being a label. The image gets it's size from the label, and then the entire button from the image (so indirectly the sizing comes entirely from the label).
Your button view should have internal constraints, based on the label and the image. These should be sufficient to give it the correct size. You don't need to implement intrinsicContentSize for that.
The button's superview does not and should not know or care what is going on inside the button. You don't directly reference the intrinsic content size, the layout system does, and if your button has the right internal constraints, it isn't necessary.
Intrinsic content size is there to allow a view to express its size as something at the very bottom of the view hierarchy, based on its display contents, such as the text in a label. Everything above that is based on constraints.
You can also use it to allow a view with non-autolayout subviews to participate in autolayout, but this can lead to a lot of duplicated frame calculation code.
My app has a bunch of horizontal tableViews inside a normal vertical tableView.
Here is a picture to illustrate:
This results in a quite nice horizontal scrolling, but it's more than I can say for the vertical scrolling. The vertical scroll is pretty laggy.
I know that each tableView will have its own reusable cells and therefore can't be shared across other tableViews. So scrolling vertically will always instantiate cells or at least that's what I been seeing.
So my question is, how to optimize the vertical scrolling without the reusable functionality?
The horizontal cells is loaded with a xib and positioned with autolayout. Each cell have at least ten subviews. There is not much blending.
[self.tableView registerNib:[UINib nibWithNibName:#"RATableViewCell" bundle:nil] forCellWithReuseIdentifier:TableViewCellIdentifier];
I know its hard to give me advise without more information, but I'm more interested if the situation with no reusing of cells changes any traditional advises about optimizations e.g the use of shouldRasterize or CoreGraphics.
If your performance is not adequate, profile to determine what is time consuming in your scenario. Then address the problems present in the profile information.
One of the reasons we have so many ways to accomplish things is that there are many solutions to various problems. Some solutions are better than others for specific tasks we encounter. I could say "10 views - costs a lot!", then you could reduce your view count and find it doesn't make what is presently slow any faster (or just makes your program as fast as it was, but less maintainable/reusable). Another example: -shouldRasterize can work for or against you. Depends on what's being drawn.
Even using CoreGraphics, you often have multiple paths you could take in order to get equivalent results. Which is faster depends on a lot of things.
Good optimizations at this point have more to do with understanding your program's (specific) problems/bottlenecks and what makes your program slow, rather than adhering to best practices and the probability that they will address the problems in the program.