I have encountered a very strange problem and I was wondering, if anyone could help me out here since I'm totally lost.
Context:
I am developing an app with a relatively simple hierarchy. Just a few view controller but quite a lot of high-res images. They are presented in a UIScrollView with some text etc. While testing it in portrait mode the scrollview didn't scroll smoothly at all. It seemed like the framerate droped to about 4-5 fps. First I thought it was because of the high-res images.
But then I turned the iPad to landscape mode and everything ran smoothly. Since the I have a separate xib-file for portrait and landscape, I thought there has to be a problem in the portrait-xib. It turned out, there wasn't. Both had the same VC-class and where therefore using the same code and both xibs are almost identical except for the sizes and positions of the views.
To narrow the problem down, I used Instrument's TimeProfiler to see whats causing the problem. As it turned out, TimeProfiler showed some calls to [NSISEngine optimize] (triggered by NSLayoutConstraint).
In portrait mode were more calls and those calls took much longer. Further down the tree I saw that in portrait mode [NSISEngine optimize] called [NSISEngine fixupIntegralizationViolations] and in landscape it didn't.
I even removed all the viewcontroller's from the app except for the rootVC and one other which is presented by the rootVC. The presented vc just contains some images, buttons and some animations. It has only one xib for both orientations and is (as all others too) layed out with autolayout.
The layout works as it should in both orientations and there are no ambiguities (as far as i can tell. at least po [[UIWindow keyWindow] _autolayoutTrace] doesn't show any).
I've attached a screenshot of the TimeProfile of the presentation process of the vc. One for portrait and one for landscape. As you can see, in landscape the calls to [NSISEngine optimize] take only a millisecond while in portrait they take over 3000ms.
Is there anyone who can tell me why that is? Or maybe has any idea what I can do to find out what the problem is?
Any help would be greatly appreciated!
Thx
Link to a larger version of the image: link
I ran into the same issue with a moderately complex view where it performed well on non-Retina iPads or a Retina iPad in portrait mode. In landscape mode on a Retina device it took 10x longer to display a popover or push another view on the view stack. I ended up replacing the XIB file with a hand coded loadView in the view controller. That appears to have eliminated the problem. Interface builder has a tendency to create excessive constraints, so getting that under control is key to good auto layout performance.
I have also opened a support ticket on this problem.
Update:
I found the cause in my situation. It was the following set of constraints:
NSArray *constraints = [NSLayoutConstraint
constraintsWithVisualFormat : #"|[sunLabel][monLabel(==sunLabel)][tueLabel(==sunLabel)][wedLabel(==sunLabel)][thuLabel(==sunLabel)][friLabel(==sunLabel)][satLabel(==sunLabel)]|"
options : 0
metrics : nil
views : labelViewsDictionary];
It specifies that 7 labels within a parent view all share the same size and all extend the width of the parent view. I believe that the excessive relational nature of the layout was giving auto layout fits, particularly because the parent view width was not evenly divisible by 7.
To resolve it, I created an array of constraints that specify the width of each label and applied those constraints. When the device rotates the width of the parent changes so I go back and adjust the constant on the constraints to be 1/7th of the parent view width. This now performs well, the process of loading a popover now takes less than 300ms rather than 2000ms.
I filed a tech support request regarding this issue and finally got the answer, that it's most likely a bug. Bug report is filed. Hopefully they'll fix it soon. If there's any news I'll update this answer.
I had same problem yesterday in an Ipad iOS6.1 device. Instrumenting the app found that the method fixupIntegralizationViolations was taking around 300 ms every time was called (around 20 times, which is a lot) making the app absolutely useless.
My problem was very similar to the one Jack Cox comments, but I solved it differently. My constraint was:
#"H:|[allButton][inStoreButton(==allButton)][onlineButton(==allButton)][sortButton(50)]|"
The issue is that the parentView here is the full iPad landscape width, so the math of this contraint was giving each button this width: (1024-50)/3 = 324.6666667.
This is usually not a problem in autolayout since it takes care of big float numbers and round them correctly, but it seems that in iPad iOS6 Landscape rounding this numbers triggers a bug that blocks the UI. To go around it all I had to do is change the sortButton with to have 52, so each button width now is: (1024-52)/3 = 324. That's all. Now the method fixupIntegralizationViolations takes around 1ms every time is called.
The interesting thing is that using 52 gives it a not decimal width in Landscape, but it does give a decimal number in portrait : (768-52)/3 = 238.666667. However, portrait seems to not have any bug and autolayout rounds the numbers correctly.
Related
I need clarification on how the container view in Swift 4 is supposed to work. I was under the impression (maybe falsely so), that if I set up all my labels, buttons, etc. inside of a container, set that container to zero for the left and upper constraints, centered it vertically and horizontally in the main view, and then pinned all of the fields within that container, then everything would be proportionally increased or decreased, depending on the screen size.
I designed my screens on a storyboard, using an iPhone 6 sized screen.
The App should be viewed only in Portrait mode, so I needn't worry about dealing with Landscape modes. I am finding out that the text fields within the container are keeping their sized fonts; when going to a larger screen (8 Plus), I am getting a large border on the bottom and right.
When going to a smaller screen (SE), most of the verbiage gets truncated. Have I misunderstood how this is supposed to work, or am I not doing it correctly?
I am almost ready to submit my first App to the Apple Store, but want to make sure that it will handle all possible sized screens. The 2 IOS courses I've been referring to are pretty vague on exactly how auto layout works. Also, I am getting over 24 warning messages that all of my fixed width constraints may cause clipping. (15 yard penalty?).
Hopefully, someone out there will have the patience to explain what I thought should be an easy thing to do. Here are screenshots of my initial view controller using each of the 3 sizes:
Originally Designed Screen, set to iPhone 6
Screen set to iPhone 8 Plus
Screen set to iPhone SE
Many thanks in advance for helping us out,
Jones
Stack views are meant to do exactly what you are trying to do. Here is a version of your app that uses stack views to create the example below. There is also a link to the GitHub page with the code - feel free to use it, tear it apart, whatever. Good luck!
https://github.com/squarehippo/Baseball2.git
I'm using autolayout to correctly lay out some views inside a UICollectionViewCell. It works fine with iOS 8, but when I try to run it on iOS 7 or iOS 6, the cells appearance varies widely everytime they are laid out (sometimes I see small changes in size and positions - one or two pixels - and sometimes big changes, resulting in some pretty messed up cells).
I swear I tried hard to find anyone with the same problem, but I couldn't. I didn't find any answer that could help me solve or even get close to understanding the problem either.
I would appreciate any inputs on how to solve or even debug this better.
MORE INFO
I'm using Interface Builder to create the view and set up the constraints. The cell's view has a total of 17 subviews, including UIViews and their subviews, and they do have a great number of constraints.
I update a UIColletionView (which includes a table of my custom cells) everytime I press a button.
What I find outrageous here is that when I run the app, everytime I press the button, the cells' subviews change their positions and sizes. I never change any constraint or frame programatically.
Also, the behavior is worst on iOS6. The frames chage a lot more and autolayout runs really slow (it take 3-10 seconds to update the collection view on iPod Touch 5th Generation, even if it has only one cell).
Worst of all, if I keep updating the UICollectionView, sometimes XCode will complain of constraints not being simultaneously satisfied. But most of the time it works just fine.
I'm also running into crashes in some devices when removing some of my autolayout-enabled views from superview. I found this is a strange behavior of Autolayout engine, which could get to some bad calculations due to float errors. I'm wondering maybe this two problems are related.
As I couldn't find any help in the entire web after searching for almost an entire day, I'm starting to think this must be a stupid error with a stupid solution. I do hope so.
Thanks in advance!
SCREENSHOTS
I'm adding some screenshots to help you visualize the problem. To get those screenshots, I run the app on iPod Touch 5th generation with iOS 6. The behavior is different on iPhone 4 with iOS 7 (it behaves much better, but I still get the elements moving around some pixels).
Everytime I press the "Update" button, I remove the view which contains the UICollectionView from its superview (the entire screen) and add it again. I do not destroy this view, it is created only once. I thought that could be the origin of the problem (some autolayout calculation buffer holding values from previous layout), but destroying it didn't solve the problem (altough it did make the displacements less frequent and disturbing, but at the cost of performance).
This is the expected behavior. This is the view I get when the app open:
Misplaced views. This is the result of pressing the "Update" button for the first time:
Result after pressing the button a second time:
Result after pressing the button a third time:
If I keep pressing the button, I get layouts alternating between screenshots 3 and 4 (or at least they look pretty like the same).
I'M GIVING UP AUTOLAYOUT AND HERE IS WHY
Well, I'm really giving up using auto layout. I've spent almost a week learning to do a lot of thing with it (specially laying out and animating views). I thought it is a wonderful and powerful feature and I learned to love it. But then I needed to support iOS6 and iOS7.
I found it only works great on iOS8 (with any device, old or not). I don't know if I'm doing something really stupid, because I can't find any threads on the internet talking about three killing problems I've been facing.
I'll list them here just in case somebody come across this thread sometime in the future with the same problem or with a solution. They are listed ordered by the priority I gave to them to why I'm giving up autolayout.
1) Performance
Autolayout runs really slow on iOS6 and a little slow on iOS7 (compared to iOS8 - remember I'm developing with XCode 6.2 and iOS8.2 SDK). The same hardware with iOS8 runs the same code just fine.
To get to this conclusion, I ran my app in two iPod Touch 5, one with iOS6 and the other with iOS8. The difference in performance was pretty clear. Loading or dismissing a simple view (11 subviews) in iOS6 could take more than 5 seconds (on iOS 8, never took more than 1). On iPhone 4 with iOS7, the same code performed much better than in iOS6, but slower than in iOS8.
I'm sure it is an autolayout related problem because, using the same code, I disabled autolayout (and size classes) for some specific XIBs and they runned stupendously fast on iOS6, while the other views kept being slow (if you are going to try this, remember to delete the old app, clean the project and build it again, or it will still use autolayout).
2) Random crashes on specific devices with iOS6 or 7 when dismissing a view controller or removing a view from its superview
The problem is clearly stated here. It seems I'm bumping into the float error problem, because I can see some e-08 numbers on the crash log.
This is a serious problem for autolayout adoption. It's a random, unpredictable - but reproducible - crash. The same layout constraint can work in various devices, with different iOS versions. But it can also crash in some of them. Example: I had a view that worked fine on iPhone 4 (iOS7) and that crashed when dismissed on iPad Air (same iOS). The solution? Change the constraint's items relation from
x.width = y.widht*0.8 + 0
to
y.width = x.widht*1.25 + 0
which is equivalent matematically, but avoided the crash.
I searched a lot if anybody had a way to know when this crash could happen or how to tackle it down forever, so I could make my views without having to worry about testing them on every device, with every iOS version, to make sure it wouldn't crash. I couldn't find a away to fix it.
This crash doesn't seem to happen in iOS8.
PS: I tried removing the constraints from all my subviews before removing the view from superview, but then the crash occurred when removing one constraint. I couldn't find any good reason to why it was crashing when removed.
3) The problem I describe in the first part of this question
It's a third priority problem because I could solve this designing the cells without autolayout. This would be a minor problem if the rest of the app do not use cells, which is the case.
But it is still a problem I cannot understand nor solve with autolayout. When I remove autolayout, the cells are displayed just fine. And they do work fine on iOS8 and I double checked if I was using some specific iOS8 feature and I'm not.
BOTTOM LINE
I'm giving up autolayout while I have to support both iOS6 and 7 or until I can find a way to fix at least the first two problems I listed above.
I've tasted the power of Autolayout and I really like it, but I can't develop worrying about unpredictable crashes hidden on some mysterious dismiss in a specific hardware with a specific iOS version. Nor can I accept the poor performance of iOS6 (sometime soon we should drop support to iOS6, though, so this will be a lost problem).
Hi im currently developing an Universal app for iPhone, iPod and iPad. I have all view controllers in both storyboards set to Inferred. It works fine on iPhone Retina and on all iPads but when you put it in landscape mode it gets all messed upp and on the iphone 3,5 inch simulator the bottom gets cut off. How can i fix this? Do i have do create seperate view controllers for landscape mode and iphone 3,5? And the write some code that recognizes if its in landscape mode and iphone 4? I thought this worked automatically. Or have i done something wrong?
There is no quick fix/answer to your question.
Since the screen size is different while using horizontal and vertical orientations - it is simply not the same canvas and thus you will need to do some manual work to set it right.
Strategy 1.
Assuming your layout is simple - there are not too many elements and all elements can theoretically fit both horizontal and vertical screen size:
You should use auto layout from the Interface builder - Look at an excellent video from WWDC
https://developer.apple.com/wwdc/videos/
(video 406 - Taking Control of Auto Layout in Xcode 5)
In few words - you set spacers to your elements, aligning them to the end of your view (dynamically), therefore you can make your element shrink and move automatically respecting the current screen orientation.
Strategy 2.
Assuming your UI is complex and will not fit both orientations:
have a different xib file for horizontal and vertical views, this can take some time, but it is a solid solution that always looks good.
You simply need to track changes in orientation and load the appropriate xib.
Your problem will only be solved if you use Autolayouting and for that you need to go through some tutorials
Ray's Tutorial
Another Very well explained tutorial
Going through the above articles will definately help you in solving your problem
Im quite new to XCode and Interface Builder, so forgive me if the solution is obvious.
I have designed a nice portrait IPhone view in interface builder (XCode 5) and have set the constraints on each of the elements (labels, text views, switches, buttons etc) so that they are positioned correctly in either 3.5 or 4 inch portait mode in the simulator.
However, when I rotate the simulator to landscape it breaks the design with elements overlaying each other and other elements disappearing (being clipped from the view) - and I expected this.
My idea of a solution is to put all of the UI elements inside a UIScrollView and set constraints on the scroll view so that it fills the screen in either portait of landscape mode.
After doing this, the portrait view is as before in the simulator, but in landscape view nothing scrolls, and none of my UI elements respect their constraints (stretch horizontally etc). Im still losing UI at the bottom and I cant scroll it into view.
I assumed that putting everything into the scroll view would simply 'fix' this issue, but the scroll view seems to do absolutely nothing at all. I have fiddled with various settings in interface builder but nothing fixes this.
There seem to be lots of long-winded solutions to this type of scenario based on code, but surely something this simple and common should just 'work'
What am I missing, or what have I done wrong, or does simple scrolling really have to be extensively coded in order to work ???
Putting all of your elements inside a scroll view won't really solve anything. Those elements would still need constraints to know how to position themselves in the scroll view. You need to be careful as well, as this solution sounds like something that goes against apples human interface guidelines. I'd advise against ignoring those, as Apple are known to reject apps that do this.
I'd say your problem is your constraints simply aren't setup correctly if elements are cover other elements and moving into the wrong places when rotated.
Annoyingly the WWDC videos section of the developer site is still down, but when it's back up, have a watch of the video of autolayout in Xcode 5, it will help explain what's going on.
If you want elements to completely change position when rotated however, you're likely to need more than just constraints, and would need to throw in some code to handle the transition between portrait and landscape. So it really depends on what the view is supposed to do when you rotate the device
OK, Ive figured it out. It IS a bug in either XCode 5 or IOS 7
I created 2 simple iphone UI's in interface builder - one in Xcode 4.6.3 targeting IOS 6.1 and the other in XCode 5 Beta 4 targeting IOS 7 beta 4.
The first app ran entirely as I had assumed, with the scroll view scrolling in landscape mode. The second app had no scrolling at all in the scroll view - so obviously a bug.
Is there any way to limit the amount of curling of that kind of presentation? I know that system automatically curls depending on content inside view of the viewcontroller that we present modally in taht way.
But thta's not working for me in my iPad app. I have only a little table at the bottom right corner of the view but the page curls more than a half.
I double checked all properties and autoresizing masks without find a solution.
Any suggestion?
I am having the same problem. Same source code for iPhone and iPad, but the iPad version is curling the page too much, leaving a lot of free space. Then I tried to only put a label on the bottom of the iPhone version and the same thing happens.
Explanation: Apparently UIModalTransitionStylePartialCurl always curls half the page, at minimum. The only reason in iPhone does not leave free space but it does in iPad is because, as the screen is much smaller, in iPhone usually your controls take not a lot less than half the page, which does not happen in iPad.
The only workaround I have found is re-designing the iPad layout so that your UI controls take more space, or just "living with it".