NSView subclass with IBOutlets and IBActions - cocoa

I have an NSView subclass that is used for displaying a custom object. The drawing logic is all in methods on the subclass. There is no view controller associated with this view.
I have added a couple of controls next to this view in Interface Builder that will be used to control the display of the object.
Is it OK to have these controls connected to IBOutlets and IBActions on the view? I know that it's possible, but is it poor design? Should I be using an NSViewController?

No that is completely fine and it's how things are supposed to connect together. There is no need to use an NSViewController as it only really helps manage the creation of the view from a .nib file and it can still only manage one view.

Related

Use NSViewController with Custom View

I have a main .xib view with parts of it being made up of custom views. At the same time I have also created separate .xib subviews (together with their respective .h and .m files). These custom classes were then connected to the custom views in the main .xib
This setup works fine however I would like to have a number of NSViewController(s) control each of the different custom views. What is the recommended way to do this?
Eg. Main.xib > contains 'custom views' > each using an NSView custom class and designed in it's own .xib
An NSViewController class would respond to events occurring in one of these custom views instead of the NSViewController tied to Main.xib
I've ended up creating NSViewControllers with XIB files instead of the custom views I had previously.
I then created NSBox components for every custom view that I had. I connected each of these to the main NSViewController via IBOutlet(s).
Finally, I attached each custom view to the dedicated NSBoxes via the IBOutlets as follows:
- (void) awakeFromNib{
[super awakeFromNib];
//instantiate custom view controller
CustomViewController* customViewController = [[CustomViewController alloc] initWithNibName:#"CustomViewController"
bundle:nil];
[self.customNSBoxView setContentView:[customViewController view]];
}
What I've tended to do is just create a new NSViewController subclass and choose the 'Create XIB' option.
From there, I instantiate the view controller subclass and add it to the view hierarchy in code.
This doesn't completely do what you are suggesting, but it does keep things more modular / easier to test. The downside is that its challenging then to setup constraints between the parent and children. I've tended to do this manually as well, or add the subcontroller's view into a NSStackView which gives you some constraints.
There's probably a better way, but this is what we used in our multi-xib project.

Replace subview of NSSplitview with custom view

I still have a lot to learn with cocoa so I may have missed something obvious here. I have a custom view I would like to display in an nssplitview which replaces the current subview there.
I have a MessageView.xib file, and a MessageView .h/.m which subclasses NSView. I created a custom view instance for my main window (the one which contains the nssplitview) through Xcode 4's built in gui builder. I created an outlet to this instance of MessageView in my window's controller.
In my controller for the window when I want to swap out the subview for the splitview it runs this
[splitView replaceSubview:[[splitView subviews] objectAtIndex:1] with:viewMessage];
viewMessage is the outlet to the MessageView.
When this code is run the display of that subview changes to be blank. I'm not sure if there is something wrong with my custom view or there is some size issue. Is there something I need to do to fit the view into the split screen view or is my custom view just not displaying correctly? I have had a difficult time finding a tutorial on creating custom subviews with Xcode 4 so I'm not sure if something could be wrong with that. The custom view just has a label and a textfield in it.
Generally, you shouldn't need to replace NSSplitView's subviews with your own. Rather, you add your own custom view(s) as child views of the default subviews on each side of the divider. You can do this in code with addSubview:, but it's probably easier to just use Interface Builder in Xcode. Drag a "Custom View" into the splitview, then in the Identity Inspector, under Custom class, change the class to the name of your custom NSView subclass:
I think (off the top of my head, not tested), if you really do need to replace the default NSSplitView subviews with your own class, you can probably do it in Interface Builder using this same method, but selecting the default subview itself and changing its class in the inspector. This doesn't work for all AppKit classes, but it may work for NSSplitView.

Switch XIB Views - Cocoa Mac

I am pretty new to coding and would like to know how to switch XIB views on a button click. IS there also anyway to add animation when switching?
Thanks,
Kevin
this is totally possible, but there are a few things you'll need to do. I imagine you are already familiar with connecting outlets to objects in your XIB, so the first thing you need to do is create the custom views in your XIB and connect them to outlets in your appDelegate. I suggest that one of the views be dragged into the window and one one be outside the window. That way, when the window loads, it already has one of your custom views as a subview. This just makes it easier to get started.
Then you're going to write an IBAction in the appDelegate and connect it to your button. Assuming that one of the custom views is already being hosted by the window, the IBAction should send a replaceSubviewWith message to the window's contentView animator like this [[window.contentView animator] replaceSubview:firstView with:secondView]; where firstView and secondView are the pointer/outlets that you declared and connected to the views in your XIB.
This is sending the animator proxy of the window's content view a message which tells it to replace the old subview with the new one. The reason for sending the message to the view's animator proxy (and not the view itself) is that the transition will be carried out with the deafult CATransitionAnimation. Because you want it to be animated, right?
The reason why you shouldn't remove one subview and then add another is because animating the removal of a subview is actually quite tricky and requires the implementation of the delegate method animationDidEnd. This is because executing an animation on a view that has been removed from the view heirarchy does not make sense. I don't know why Apple hasn't changed this, but for now it will be one of the enduring quirks of CoreAnimation.
Let me know if that helps. I am happy to clarify! And welcome to Cocoa!
An easy way to do this is to use a tabless NSTabView- you can lay everything out in IB so the pain is minimal.

Why do UIViewControllers have xib files and UIViews do not?

When I create a new UIViewController in xcode, it offers to make me an associated nib for the interface. However, when I create a UIView, it does not. If my understanding of MVC is correct, views should really be the parts that contain the interface elements (i.e. the nib) while view controllers are the parts that hook the functionality to the views they control.
I'm sure I'll be able to get it working together either way, so this is more of an exploratory question.
This seems like a case where I'm missing some fundamental understanding of how these two parts should be used. What am I missing?
Because UIView is usually not used in such way.
However How do I associate a nib (.xib) file with a UIView?
The answer I eventually got that satisfied my interest was roughly this:
The job of a view controller is to manage a view hierarchy. Interface Builder is an excellent tool for creating view hierarchies. Xcode offers to create a .xib when you create a new view controller because chances are high that you'll want to load the controllers' views from a .xib.
.xib files aren't necessarily meant to hold every UIView (or subclass) that goes into the view, just a general outline of views that don't change during the life of the view. The other UIViews are much easier to create programmatically since they change often.
I had a similar confusion. Basically (according to the MVC) the View is contained inside the Controller. In the iPhone this means that UIViewController has a property called 'view' which is a UIView instance.
A XIB file (and this is not mentioned often) is a serialised UIView instance. It is roughly an XML sub format which represents a UIView with all its subsequent views. So when you create a UIViewController, a UIView is created in the form of a XIB and bounded to that controller.
A new UIView therefore does not have a XIB because they are essentially the same thing...

IBOutlet not getting set in Cocoa MVC project

I might not be using IBOutlet correctly, or some other subtlety with how NIB files work is causing me trouble - any help would be much appreciated (feel free to propose an alternate way to accomplish what I want).
I have a View object and a Controller object. Both are in the NIB. The Controller's init is also called when the NIB is loaded and the View is initialized in the 'awakeFromNib' callback.
I need a way to connect these two objects - specifically, enable the 'View' object to call functions on the Controller.
Based on documentation online, the way to get these connected is to define an IBOutlet in the View and connect it to the Controller in the Interface Builder. So i created an
IBOutlet Controller* _controller;
in the View interface and graphically connected it to the Controller object in Interface Builder by making a connection from the View to the Controller and assigning the _controller outlet to the Controller (the blue Generic Object box in Interface Builder).
At runtime though, _controller is always _nil. I have verified that the Controller's init was indeed called.
Is there something obvious I'm missing about this?
Any simpler way to connect these two? Since they're both created by the NIB I don't have a common object that has a pointer to both.
Try accessing the IBOutlet in viewDidLoad instad.
When awakeFromNib is called not all the IBOutlets are populated (even though the documentation seem to imply it).

Resources