Autolayout issue for UITextField in ios - ios

I created UITextField in storyboard. And added its constraints also. I want search icon on left side of UITextField. The code for adding search icon is as follows:
self.searchTextField.leftView = searchIconImage;
self.searchTextField.leftViewMode = UITextFieldViewModeAlways;
[self.searchTextField addTarget:self
action:#selector(textFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
My application is working fine on iOS8 and its crashing on iOS7. The error is as follows:
Assertion failure in -[UITextField layoutSublayersOfLayer:], /SourceCache/UIKit/UIKit-2935.138/UIView.m:8794
2014-11-05 12:54:33.377 WattUp[1722:60b] Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. UITextField's implementation of -layoutSubviews needs to call super.'

So I ran into this same error a few days ago as well. It turns out I was trying to layout subviews inside my UITextfield subclass, setting properties on them, moving them, etc, but was never explicitly telling the view to lay itself out (i.e. calling [self layoutIfNeeded]).
iOS 8 seems to force to a view to layout all its subviews, and then configures constraints on it. iOS 7 won't, and needs you to explicitly tell views to redraw their subviews when you change if you're using autolayout.
In my case, I had subclassed UITextField and added a label to the side. I configured the frame of the label by adding constraints to the UITextfield. One of the public methods I could call on my class was
- (void)setLabelText:(NSString *)newText{
self.sideLabel.text = newText;
}
This caused my application to crash when a view controller appeared containing my subclassed textfield. By add layoutIfNeeded everything works fine in iOS7 and iOS8.
- (void)setLabelText:(NSString *)newText{
self.sideLabel.text = newText;
[self layoutIfNeeded];
}
This needs to be called every time you change a part of the view in your subclass. This includes the setup when you add subviews, when you change view properties, anything really. Before the function that's changing your view returns, call layoutIfNeeded on your view. This seems to apply for a few standard UI controls including UITextfield, UITableView and UICollectionView, though I'm sure there are others. I hope this was clear enough and helped solve your problem.
The error you're getting isn't super useful, and didn't even apply in my case. Though I was receiving the exact same error, none of my views implementing layoutSubviews, and thus were all using the [super layoutSubviews] method.

I solved this by subclassing UITextField and reimplementing 2 methods:
- (void)setText:(NSString *)text
{
[super setText:text];
[self layoutIfNeeded];
}
- (void)layoutSubviews
{
[super layoutSubviews];
}
really annoing thing. Apple makes programmers cry so often

Related

Can't use UICollectionView in UIInputViewController for keyboard extension

I have created a UICollectionView subclass which I want to use to provide the keys in a UIInputViewController as a keyboard extension. But I have found that attempting to instantiate a UICollectionView will cause the keyboard to crash whenever the user switches to it. Thinking it might be something to do with my UICollectionView subclass, I tried replacing it with a plain UICollectionView, but this caused the same problem. I even tried just instantiating the object but not doing anything with it, as in the extract below, but it still crashed the keyboard.
// KeyboardViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
UICollectionView *collect = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
}
I can't get any debugging on the keyboard, because the debugger attaches to the main app's process, so I can't tell what is causing the crash. I would really appreciate any input on whether it is possible to use a UICollectionView on a keyboard extension, and if so, how I can get around this issue.
It turns out that the problem was being caused by simply importing the header for the UICollectionView subclass, even though I didn't use it. When I removed the import, I was able to instantiate a plain UICollectionView and add it as a subview of the keyboard.
This meant I had to do some fairly nasty stuff to abstract the delegate and datasource methods into a separate class so that they would be reusable, but it works.

Updating Constraints programmatically iOS

I need to update a constraint programmatically in my project to adjust a view's height accordingly (based on different subviews). I've made outlet of the constraint in my controller but facing an issue.
when I try to update this for the first time (in viewDidLoad or viewWillAppear method), it's not updated. and if i update it afterwards (because of some rotation etc), then it is done correctly. Kindly tell me why this is happening and what is the right way/place to do this? (As i feel that the constraint is updated somewhere again after my updation in viewWillAppear/DidLoad).
I tried view.layoutIfNeeded as well but it didn't help. I guess it has something to do with viewDidLoad and other viewController delegate methods
P.S. I'm also using size classes in my project but I think it has nothing to do with that as it's working in some cases.
Updating constraints may not work in viewWillAppear.
It will, however, work in viewDidAppear.
There are other places you may overwrite, such as: (using static BOOL shouldRefreshView = NO; for the first time)
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if(shouldRefreshView) {
shouldRefreshView = NO;
[self.view layoutIfNeeded];
}
}

Application crashes in iOS 7 when place holder text is added to text field

My application crashes in ios7 when i add a placeholder to text field ,the same works fine in ios8. Added controls programmatically with auto layout
As suggested i added [self.view layoutIfNeeded]; at the end of viewDidLayout delegate method but still the app crashed with the below exception
Assertion failure Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. UITextField's implementation of -layoutSubviews needs to call super.'
It is very important where you add your constraints programmatically. You should not add them in one of the layouting methods callbacks (like layoutSubviews or viewdidLayoutSubviews). That is because the system is expected to have the views layout after these methods are called and if you add new constraints after the views were already layouted and a new layout cycle is needed, there will be a crash.
I suggest you think about another method where you could add the new constraints. If there is no other place that would work for you, try adding the constraints before you call the super method, not the other way around.
So something like this:
- (void)viewDidLayoutSubviews {
// Add constraints
[super viewDidLayoutSubviews];
}
If you could post some of your code, I would me more than happy to help you further :)

Where to add UI objects when programmatically creating UI (instead of .xib/storyboard)

In the UIViewControllers where I don't use .xib files, I've been creating my UI elements in the viewDidLoad methods. E.g.,
- (void)viewDidLoad {
[super viewDidLoad];
// Setup table
self.tableView=[[UITableView alloc] initWithFrame:self.view.frame];
[self.tableView setDataSource:self];
[self.tableView setDelegate:self];
[self.view addSubview:self.tableView];
// Setup custom cells
UINib *lessonNib=[UINib nibWithNibName:#"CustomCell" bundle:nil];
[[self tableView] registerNib:lessonNib forCellReuseIdentifier:#"CustomCellID"];
}
For the most part, this is working fine. But, in the process of investigating a bug associated with dynamic cell heights, I'm curious: is this the appropriate spot to add my UI elements?
Thanks for reading.
I would say it is the right place, yes. Since this method is only called once for sure and is called before anything of your view is shown on screen. And therefore you don´t risk creating them twice or even more often or too late.
But your layout should be done at a different place - in viewWillLayoutSubviews:
When a view's bounds change, the view adjusts the position of its subviews. Your view controller can override this method to make changes before the view lays out its subviews. The default implementation of this method does nothing.
You could also overwrite the corresponding viewDidLayoutSubviews
Regarding your comment: yes, layout information is not yet present in viewDidLoad, self.view.frame for example is not guaranteed to be the actual frame that your view will be displayed in later on. Further more a frame change by some part of your code would cause your UI to not respond if you set their size and position only on load.
Note: Setting up your subviews via code is far more tedious than just designing them in a storyboard - I would heavily recommend that if you don´t have serious concerns against using them.

Can't set UILabel#preferredMaxLayoutWidth in layoutSubviews after constraints are in place

What are your best practising when you subclass UIView?
I'm trying to do a view for a viewcontroller entirely in code, using the new ios 6 autolayout.
So I've subclassed UIView and setup the basic constraints in #initWithFrame (should I do this in #updateConstraints?). The problem is that I have an UILabel with dynamic text and variable width so I have to setup #preferredMaxLayoutWidth after the constraints have determined a frame, so I think #layoutSubviews is the best place to do that, but doing that results in a NSInternalInconsistencyException: Auto Layout still required after executing -layoutSubviews. MyView's implementation of -layoutSubviews needs to call super. (RuntimeError)
Before you asks I'm sure I have called super in every method I overridden.
Any idea?
Perhaps what you need here is to not have your view call [super layoutSubviews], but UIView, the ancestor, call its [super layoutSubviews].
This can be achieved not by subclassing, but implementing a category of UIView, which would have layoutSubViews function implemented, calling super. If I could have your code I could have tried. Someone has tried it successfully here.
Again, this does not guarantee that this will be fixed. There seems to be many bug reports concerning this in Apple forums. Unfortunately, we can't browse others' bugs in Apple portal, we can just file our own.
As a workaround, I would also suggest if any of your constraints conflict with your
preferredMaxLayoutWidth argument: try increasing or decreasing it. As per the overriding order of its own, it can change things, and who (other than Apple) knows - it maybe fixed. Fingers crossed!
This seemed to work for me, I can't explain why, but it did.
-(void)layoutSubviews
{
[super layoutSubviews];
layout code here, including updated constraints
[super layoutSubviews];
}

Resources