Assertion failure in -[UITableView layoutSublayersOfLayer:] - objective-c

I want to use an UISearchDisplayController on UIViewController, that includes an UITableView.
I use Autolayout. When i try to put the SearchBar (_searchBar) in the tableHeaderView with
self.tableView.tableHeaderView = _searchBar;
I get the error
'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. UITableView's implementation of -layoutSubviews needs to call super.'
Disabling Autolayout, the error disappears, but i need Autolayout...
The error appears, when I use Custom Cells or StandardCells...
The error appears, when the TableView has no rows...

As a general solution to this problem, or at least a way of finding the cause of it:
Turn on exception breakpoints
Subclass UITableView and override layoutSublayersOfLayer:, just calling super
Run your app - you will stop in your new method
In the debugger, type po [self _autolayoutTrace]
This will show you a printout of every view in the window, with the views where auto layout has not been able to come up with a solution highlighted by asterisks or AMBIGUOUS LAYOUT. These are the views you need to investigate the constraints for.

When adding a subview to UITableView there are some specific requirements for the subview. Consider adding the subview to another view(superview) in your controller instead of UITableView.
"Auto Layout still required after executing -layoutSubviews" with UITableViewCell subclass

Related

Poor UITableView performance when in UIPopoverController with custom background

I have a following situation (testing on iPad, iOS 5.1):
There is a UIPopoverController with UINavigationController inside and custom popover background view (subclass of UIPopoverBackgroundView).
There is a generic UIViewController (let's call it VC1) as the root VC in the Navigation Controller.
I push another UIViewController (VC2) with UITableView on the Navigation Controller stack.
Effect:
Table scrolling is choppy (looks like 10-15 fps). For testing purposes I use a simplest possible UITableView, without images etc. so it's NOT caused by bad UITableView implementation.
Scrolling is not choppy if the VC2 is the root view controller of
Navigation Controller, even with the custom Popover background.
It's also not choppy if pushed as the second VC but I don't use custom bg view class for UIPopoverController.
I log each of the overriden methods inside my UIPopoverBackgroundView subclass, and they aren't called constantly or anything, which could theoretically cause performance hit. I'm going to debug the problem further but maybe someone has already solved it before?
Or maybe someone has good suggestions on how to find the culprit? I tried looking into time profiler for offending function calls, but I didn't find much there...

Xcode's auto layout is only effective in viewDidAppear and this is very problematic

After upgrading my project to iOS 6, I realized that auto layout is only effective in viewDidAppear and most of my code expects the view's frame to be available in viewDidLoad. This limitation renders the really nice auto layout feature almost useless for me. Is there any suggestions to help me use auto layout?
For example, sometimes the developer needs to adjust information about a subview based on where auto layout chooses to place that particular subview. The subview's final location cannot be ascertained by the developer until AFTER the user has already seen it. The user should not see these information adjustments but be presented the final results all at once.
More specifically: What if I want to change an image in a view based on where auto-layout places that view? I cannot query that location and then change the image without the user seeing that happen.
As a general rule, the views frame/bounds should never be relied on in viewDidLoad.
The viewDidLoad method only gets called once the view has been created either programmatically or via a .nib/.xib file. At this point, the view has not been setup, only loaded into memory.
You should always do your view layout in either viewWillAppear or viewDidAppear as these methods are called once the view has been prepared for presentation.
As a test, if you simply NSLog(#"frame: %#", NSStringFromCGRect(self.view.frame)); in both your viewDidLoad and viewWillAppear methods, you will see that only the latter method returns the actual view size in relation to any other elements wrapped around your view (such as UINavigationBar and UITabBar).
As told by #charshep in a comment, calling view.layoutIfNeeded() in viewWillAppear can do the trick.
Quote of his original comment
I had trouble getting a table view to appear at the correct scroll position when pushing it [...] because layout wasn't occurring until after viewWillAppear. That meant the scroll calculation was occurring before the correct size was set so the result was off. What worked for me was calling layoutIfNeeded followed by the code to set the scroll position in viewWillAppear.

UIViewControllerHierarchyInconsistency View Controller exception

I'm trying to change the detail view in a splitViewController, i have the UIViewControllerHierarchyInconsistency exception when i do
self.detailView.view=view.view;
I've controlled if there are other viewControllers in xib files and i also used method removeFromParentViewController, but i've the same exception.
The error is only in iOS 6 but not in iOS 5, in iPad simulator.
Terminating app due to uncaught exception 'UIViewControllerHierarchyInconsistency', reason: 'A view can only be associated with at most one view controller at a time! this is the error, view.view is the view i want to load in the splitViewController, there is no other code, i do only the change of the view in the split, i used removefromparentviewcontroller because i want to remove the association to the viewController to remove the exception
Is your splitViewController an instance of UISplitViewController?
http://developer.apple.com/library/ios/#documentation/uikit/reference/UISplitViewController_class/Reference/Reference.html
If so, you're doing something fundamentally wrong. The UISplitViewController is simply a container for two view controllers, a master view controller and a detail view controller. It is then up to your view controller to decide how to deal with interactions and such. removeFromParentViewController is only used in View Controller Containment, and as such doesn't seem applicable here.
Read the documentation in the link above to see if it meets your needs, but if I understand, you need to set your view controllers in the split view, not your views.
To do you, you need to do:
// Assume this is initialised correctly
UISplitViewController* splitViewController = [UISplitViewController alloc] init...];
// Assign the two view controller you want to be used in the split view controller
splitViewController.viewControllers = #[masterViewController, detailViewController];
If this isn't applicable, then please provide your code so that a correct solution can be made. Your descriptions have been rather vague as to what you're actually doing.

UIScrollViewDelegate scrollViewWillEndDragging:withVelocity:targetContentOffset: warning

I have two UITableViews on one view controller (view controller is their delegate). One of them will be depending on scrollViewWillEndDragging:withVelocity:targetContentOffset: (I want to do some kind of custom pagination). The other one have pagingEnabled property set to YES and when I try to scroll it for the first time XCode gives me warning
2012-09-07 16:46:39.672 test[17393:707] Stop offset can not be modified for paging scroll views
even though the code of the method is at the moment:
-(void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
return;
}
When I delethe the method scrollViewWillEndDragging:withVelocity:targetContentOffset: everything seems to be all right. Do I need to try to make another delegate (without that method) and make it UITableView with pagination delegate, or should I just don't worry?
The reason that you are seeing this warning in the console is because the method scrollViewWillEndDragging:withVelocity:targetContentOffset: has no effect when the scroll view has paging enabled. The documentation states the following.
This method is not called when the value of the scroll view’s pagingEnabled property is YES.
In other words, Xcode gives you a warning, but, as #tiguero indicates, it is best to check in each delegate method which table view (scroll view) is sending the delegate message.
As for the warning, you can ignore this warning since your controller is the delegate of both table views, one of which has paging enabled.
I am a bit confused about what you are trying to achieve here. Nevertheless if you have the same view controller that act as a delegate for two UITableViews, I recommend to have those delegate methods implemented and check which scrollView you are working on by checking the scrollView variable passed in parameter of your delegate method.

UITextView: Must I always resignFirstResponder?

Must I always resignFirstResponder for a UITextView? Or, will this happen automatically when its view controller disappears?
I'm asking because I'm having an issue similar to iPhone Objective-C: Keyboard won't hide with resignFirstResponder, sometimes, where the keyboard stays up even when the nav controller pushes and pops other view controllers. The keyboard works, and when I hit done, it unfocuses the UITextView (i.e., the cursor disappears), but the keyboard stays up.
I never found out why this is happening, but maybe it's due to not doing resignFirstResponder before pushing another view controller, but I thought it was optional?
At a total guess, the UITextView has a reference to the view controller (as its delegate) but does not retain it. When you go to the next screen, the controller is dealloced and then the UITextView (which has perhaps been retained by something else) tries to call back to the dealloced controller and crashes. When you call resignFirstResponder, you reverse the order this happens, and therefore no crash.
The way round this to add a textView.delegate = nil call in your view controller's dealloc method - obviously put it before you release the text view.
The contract between a UITextView and it's delegate says that the delegate will send -resignFirstResponder when the text view is done editing. This informs the framework that the view is done editing, fires the events relating to that (willEndEditing and didEndEditing), and allows other parts of the responder hierarchy to react accordingly. Failing to do so might work, but it's not following the contract (that's all a protocol is) it agreed to.
I don't think you have to because the Xcode Sample UICatalog UITextField doesn't call resignFirstResponder before the TextViewController is popped.
The reason the keyboard got stuck for me is that I was having the same view controller present two view controllers modally at the same time, one after the other. UIKit didn't like that.
Calling resignFirstResponder makes sure that the text property contains the actual text shown in the control.
Depending on the state this is not always necessary, but if your controls have resigned first responder, you know that you're working with valid data.