Subview doesn't appear on Mavericks; works on Mountain Lion - objective-c

I've found a problem in my OSX app that I think is a Mavericks bug.
I have the following hierarchy:
NSView
->NSScrollView
->NSClipView
->NSTableView
When the scroll view doesn't contain any records I'm creating an overlay view as a subview of the NSView, and positioning it above the other subviews. I do this using:
[containerView addSubview:overlay
positioned:NSWindowAbove
relativeTo:nil];
FYI, the overlay view is a custom NSView subclass with a drawRect to draw the overlay itself.
On Mountain Lion this works fine, but on Mavericks the overlay does not appear. Googling around I think this is because the overlay is not being positioned above the other sibling views.
I found these links for reference:
Display Order Messed Up
Maverick Issue When Adding Subview on NSView (Stack Overflow)
The second link suggests the following code to fix the issue, which it appears to do, but as I don't have any layer-backed views in my app this feels a bit off:
[overlay setWantsLayer:YES];
Can anyone suggest a workaround for this problem other than the one suggested?
EDIT: I've found that if I put an Xcode breakpoint in the original code (without the workaround) at the point after the subview is added the subviews get added correctly, and my overlay view is displayed. If I remove the breakpoint, the overlay view is no longer displayed. Does this behaviour indicate anything?
Thanks
Darren.

It looks like you've been bitten by overlapping views:
Note: For performance reasons, Cocoa does not enforce clipping among sibling views or guarantee correct invalidation and drawing behavior when sibling views overlap. If you want a view to be drawn in front of another view, you should make the front view a subview (or descendant) of the rear view.
from Apple's Working With A View Heirarchy.
As you note, the common recommendation to fix this is to is to set a layer. However since 10.4 you can hide a view using setHidden:, see Hiding Views in the above reference. This may solve your particular problem as your overlap appears to be total (you don't want to see parts of both views, only one of them).
HTH

Related

Autolayout works when viewController is loaded from XIB but does not work when loaded from Storyboard

I Have a project here. Autolayout constraints is working only when loaded from a Xib file.
When you run the project you will see a single screen with a NSPagecontroller on it that has two views (swipe left/right to get the other view).
Both views are exactly the same with the exact same auto layout constraints on it. One is loaded using Xib, while the other is loaded using Story board.
Try resizing the window when the xib loaded one is on screen. You can see every thing resizes correctly. Now swipe the screen left. Try resizing the window now. The view loaded from story board will not autosize.
Is this Apple bug?
The views are not exactly the same. If I delete the view in the storyboard, and copy-paste the view from the xib, then the storyboard version behaves as expected.
The trouble with all of this storyboard/xib constraints goodness is that they are a complete pain to debug if something goes wrong.
Try spot the difference:
(1) ViewController.xib
(2)Storyboard
For this reason, I tend to handle all of my constraints in code these days.
Top left button comparison:
(1) ViewController.xib
(2)Storyboard
The other buttons constraints differ also.

NSPopover padding content on one side

I have two NSPopovers, both of which are set up exactly the same (just linking a custom NSView from IB). Both pop up just fine, but one appears to offset the content by about 20px.
This NSPopover is (properly) not padding the content...
but this one adds about 20px from the ride side.
Here are the two views laid out in IB
As you can see, the search bar should be pinned to the right side like it is the left, but for some reason it is not. At first I thought it was a contraints issue, but after messing around with them for a while I can confirm it is not.
Any clue whats up?
EDIT: Decided to subclass the view and fill its rect, got some very strange results! The view appears to be offset. I have no clue why this is...
From here, this caught my eye (emphasis mine):
The principle circumstance in which you should not call
setTranslatesAutoresizingMaskIntoConstraints: is when you are not the
person who specifies a view’s relation to its container. For example,
an NSTableRowView instance is placed by NSTableView. It might do this
by allowing the autoresizing mask to be translated into constraints,
or it might not. This is a private implementation detail. Other views
on which you should not call
setTranslatesAutoresizingMaskIntoConstraints: include an
NSTableCellView, a subview of NSSplitView, an NSTabViewItem’s view, or
the content view of an NSPopover, NSWindow, or NSBox. For those
familiar with classic Cocoa layout: If you would not call
setAutoresizingMask: on a view in classic style, you should not call
setTranslatesAutoresizingMaskIntoConstraints: under autolayout.
Does it apply to you?
if you have an outlet to your content view, you should be able to force it into place with:
[contentView setFrame:[[contentView superview]bounds]];
or more modernly I guess...
contentView.frame = contentView.superview.bounds;
Proplem solved, but I still don't exactly know why it required solving. The NSPopovers content view (or at least mine) requires an origin point of X: 13, Y: 13. For some reason, only one of my views was getting this value.
To solve this, I subclassed NSView and overrode the setFrame method forcing its x and y to always be 13, 13
-(void)setFrame:(NSRect)frameRect {
[super setFrame:NSMakeRect(13, 13, frameRect.size.width, frameRect.size.height)];
}

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.

UISplitviewController and UINavigationController

I have a splitviewController for my iPad app that uses a uinavigationcontroller in its detail view (right view controller). Everything is hooked up in interface builder and after calling:
[self.window addSubview: splitViewCpntroller.view]
I get the left and right views to display.
The problem is, the navigation bar's y position in my right view is wrong and offset a bit (I think 20px) downwards so that there is a gap between the status bar and the right view's navigation bar.
I've spent the whole afternoon trying to figure out what's wrong but I didn't find anything. Since its all hooked up in IB I can't show you much code.
I'm sure it's a simple thing I'm missing and since it's IB it's probably hard for you to follow what exactly I was doing - but maybe one of you encountered this before?
This is one of those questions that comes up pretty often, but for some reason it's hard to remember the answer. However, I think the root of your problem is that your view controller's view has a height that's too small -- try adding 20 pixels to the height, and also check its position.

Flipping between views has UITableView position issue

I have a UINavigationController within a UITabBarController. Within the navigation controller I have a ViewController that looks after flipping between two views using transitionWithView:duration:options:animations:completion one of the views i am trying to show is a TableView.
The problem is when showing the TableView it is off position.
and the flip view
I have tested flipping between two standard views without issue, it is only the TableView that shows off position. Also when the Tableview has more data then can be shown on screen the bottom rows are hidden by the Tabbar. It looks like the frame size is wrong but I am not sure how to proceed to fix the problem.
Full test project and code can be found on GitHub
Any suggestions or help is greatly appreciated.
The root of the problem is that you are using UIViewControllers (FlipSide and FlipMain) as subviews for FlipController which is itself a UIViewController. Prior to iOS 5 this was not supported and inevitably led to problems. iOS 5 adds support for a view controller hierarchy but requires that you use the appropriate new methods.
You have a couple of choices: restructure the view controllers so they are not nested, rewrite the sub-controllers as UIViews, or use addChildViewController to add the subcontrollers.
I've forked and modified your original code here to illustrate that changing to UIViews resolves the problem with layout.
It's a bit hard to answer without the full code, but I would try playing with the "wantsFullScreenLayout" property of your view controllers. I say that because the offset seems to be 20px high, which corresponds to the status bar's height...
Let me know if this helped ;-)