How to create a reusable form using Cocoa bindings? - cocoa

I want to make a user interface in which the user can edit two objects at the same time. The main window would have a vertical split view and a form on each side of the view.
The problem is that the two forms are identical and I don't want to duplicate the view components in the interface builder. I want to create the form one time and add a reference to it in each side of the split view, each one using a different object source.
I could use a NSForm, but the form is not a simple grid of outputTexts and inputText. They have a master table, and diverse kinds of inputs types, like combos, in the detail.
How do I create the reusable form using the interface builder? Or how can I do it programmatically? Do I have to create a subclass of NSView and add the individual components in the code?
Thanks,
Juliano

Similar to the way you create a NSWindowController subclass which manages a nib containing your window, you can create a NSViewController subclass which manages a nib containing the view, then instantiate it twice and (programmatically) add the two views to each of the subviews of the split view. See the code in this question for a (partial) example.

If you build one form in IB, you can option-drag it to the other side of the split view to create an exact copy, including bindings and connections.

Related

developing multiple panels in a single view

I'm new to cocoa development, and been trying to look for something similar in the attached image.
Basically an app with multiple views or sections or panels, where I'd link separate classes to each of them instead of one Delegate class doing everything.
I'm also confused between the old xib and the new storyboard style and wondering how can I accomplish the same, like what kind of visual objects to use. attached images explains where I'm trying to get at.
In Mac OS Cocoa it's common to just uses plain NSView objects to hierarchically subdivide complex views.
If you also want visual dividers there's NSBox. For resizable parts use NSSplitView.
Regarding the controller tier it's also pretty common to set up individual controller objects for separated panes (subviews) in a window.
You are talking about one single view. So what is possible would be to create a background view and then add multiple custom subviews (NSView subclass), each with their own custom class to control them, and even custom controllers.
As to accomplish something that looks similar to the screenshot, you can select a few UI elements in interface builder and do Embed In > Box to group them like in the screenshot.

Designing UICollectionView cells in nib with Interface Builder (without storyboard)

I am trying to design a custom UICollectionViewCell prototype (in Xcode 5.0.2), however Interface Builder doesn't let me add a cell to my UICollectionView while designing a nib. I can set the number of items (cells) and Interface Builder creates and displays cells perfectly if I'm using storyboard, but I can't add a cell to my collection view in a nib. I've tried:
Drag and dropping collection view cell into collection view manually from the object library. (fails: doesn't let me drop the cell anywhere in my view)
Creating my collection view with cells in storyboard and copy-pasting the whole view into nib. (fails: collection view is copied but the cell is gone)
Creating my collection view with cells in storyboard, opening the storyboard as source code, finding my collection view cells, copying the relevant XML, opening my nib as source code, pasting it inside my collection view in XML. (fails: unable to open the nib in Interface Builder, it gives errors. When I remove the cell from source code, it opens again. Do not try this if you don't know what you are doing.)
I've also seen several questions about the same issue:
Is it possible to create prototype cells in Interface Builder without story boards?
Custom Header in UICollectionView with Interface Builder without Storyboard
Prototype Cells in a nib instead of a storyboard
They all point out to doing them programatically and/or using another nib for the cell. I know how to do them, but is there any way to design the collection view cell, inside a collection view inside the same view in a nib, just as in storyboard? Why doesn't Interface Builder let me do that in nib where it allows (and even encourages) perfectly using storyboard?
The simple answer is no, this cannot be done. Think of a storyboard as a collection of XIBs. A XIB simply defines the facets of a particular view so that it can be constructed at runtime.
Regarding collection views and their storyboard implementations, it's important to understand that a storyboard allows for nesting of viewcontrollers and defining collection views with their XIBs because that keeps the fundamental paradigm of storyboards coherent. Since a storyboard is the means of defining the "story" or scene of an application it is only natural that it allows for the declaration of the reusable views for use inside a collection view.
The same cannot be said for XIBs because the fundamental idea behind XIBs is in reusability. This will allow a collection view defined in a XIB to have any cells used with it as long as the controller registers these classes with the collection view. This way you get the benefit of reusability as another controller can use the same XIB and register different cells etc.
So I think it would be far more confusing to allow for the declaration of the supported cells of a collection view inside a XIB since that breaks the single responsibility principle(if it can be called that) that XIBs aspire to.
Your best solution would be to define a custom collection view subclass that registers the relevant cells on instantiation, and then use this class in your XIB.

Create tables with mixed content

I must create a table with five rows. The first row contains a label and switch button, the remaining 4 rows contain simply a label.
This table has not to be modified.
Then, I used a storyboard to design table as specified above; now, I need a function to manage user's pressure on any row. Anyway, if I associate an UITableViewController class to my storyboard and run simulator, the table appears empty, because the methods of controller to fill rows have not been implemented. But I don't want to implement them, since my table has already been designed through the storyboard.
How can I design a controller simply managing my storyboard as it is, without defining functions trying to modify the structure I designed, but allowing to handle user's interactions as well?
If I loaded my storyboard into an UITableViewController through the use of function instantiateViewControllerWithIdentifier, would I have my table as I designed it, giving labels/table/button an identifier? How could I manage user's interaction in this case? how could I access the table and its field/row numbers?
Alternatively, how could I create my table programmatically, with a label and a button on first row?
If you need to easily use the standard switch cells, label cells, and other standard UI cells, then I'd strongly recommend you check out the free Sensible TableView framework. Should save you a ton of time.
The tableview you designed with storyboard has a custom class, it's your view controller. Even you've finished the design of your tableview with storyboard, you still have to implement the delegate & datasource methods in your view controller. In your case, you need to implement "tableView:numberOfRowsInSection" to return 5, and "tableView:heightForRowAtIndexPath" if your custom cells have different height.
You should create custom tableview cells to manage user's interaction. Design the cells in storyboard, implement the logic in your custom UITableViewCell classes. Set the cell's custom class to your custom UITableViewCell classes. Pass users' interaction events to your UITableViewController with delegate.
Create UITableView programmatically is not very different. Create an UITableView and add it as subview. Make sure you set self as the delegate and datasource of the tableview. Implement all the delegate & datasource methods in your ViewController. Create a custom UITableViewCell with button and label programmatically, and return it in "tableView:cellForRowAtIndexPath" when "indexPath.row == 0"

Sharing an NSArrayController between multiple views in separate NIB files

First, some background: I am trying to implement a master-detail interface in Cocoa (for OS X). That is, I have a window with two NSTableViews that display two different types of objects. For this question, let's say they are warehouses and packages (to pick an example that is analogous to my actual problem.) Selecting a row in the first table view (on a warehouse) will display a list of packages which belong to that warehouse in the second table view. For the model part, I currently have an NSMutableArray called warehouses of warehouse objects, and each warehouse object has an NSArray of package objects. One thing to note is that the warehouses variable is modified after the NIB files are loaded, so the NSArrayController has to be notified.
Now, I've tried to organize it so that the "master" is in its own view object, and the "detail" is in its own view object. This means that there are three NIBs: a WarehousesView NIB, WarehouseDetailView NIB, and a MainWindow NIB.
The WarehousesView NIB contains an instance of a WarehousesViewController (subclassed from NSViewController) and the view itself.
The WarehouseDetailView NIB contains an instance of WarehouseDetailViewController and the view itself.
The MainWindow NIB contains the main window, an instance of MainWindowController, and an instance of both WarehousesView and WarehouseDetailView. The window itself contains an NSSplitView, and the views of the split view are connected to the corresponding view instances in the NIB file.
That brings me to the first half of my question:
1) Is this a good way of splitting up the application views for a Cocoa application? To me it makes sense, because at a later point more details about the warehouse besides a list of its package inventory might be added to the WarehouseDetailView.
It's an important question, because everything works just fine if I skip creating views, putting all controls in the window directly and put everything else, including NSArrayController instances corresponding to Warehouses and Packages, into the same NIB file. I don't need to ask the second half of the question if I shouldn't even be doing it this way.
The second half of the question is basically:
2) Where should I place the NSArrayControllers corresponding to Warehouses and Packages if I split it up as described above so that the master-detail interface still works? Currently I am using Cocoa bindings, so somehow the content array of the Warehouse NSArrayController needs to bind to my warehouses array, and the content array of the Packages NSArrayController needs to bind to the selection of the Warehouse NSArrayController
I've tried a few things, and I couldn't get anything to work completely. Specifically, I've tried putting the NSArrayController for Warehouses into the WarehousesView NIB and the NSArrayController for Packages into the WarehouseDetailView NIB. The problem with this approach is that I cannot figure out a way to bind the Package NSArrayController to the selection of the Warehouse NSArrayController. The other thing I've tried is (1) putting both NSArrayControllers into the MainWindow NIB, (2) connecting those NSArrayControllers to IBOutlets in the MainWindowController, then (3) passing those variables to their respective view controllers via their constructors, (4) exposing them as properties in the view controllers via KVC, and (5) binding the necessary table columns in a view to the array controller through the File's Owner. The result was that nothing appeared, but there were no errors either. If one of these approaches is the preferred way to do it, I can give more details to help see if I am doing it incorrectly.
Thanks in advance!
Edit: I did look at this related question, and they seemed to be using separate instances of NSArrayControllers for each NIB file if I understood it correctly, and that didn't seem to make sense from a design point of view, but perhaps I am wrong?
Part 1: You can certainly do this. I'd say it's a matter of preference. Personally, then, if the views were going to be displayed simultaneously in a window, I would keep them in the same nib.* Modularity is also a good thing, though.
Part 2: You can put the array controllers wherever you like, really. The only thing you need to worry about is getting each object the references that it needs to the information you want it to have. If you want my 2ยข, I'd say put each in the nib with the view its contents will be displayed in. That'll make your detail view setup more difficult, but it continues the modularity you seem to be going for.
You have to remember that every object in the nib is a real instance. The nib allocates and inits them for you; if you put a MyClass object in one nib, and a MyClass object in another nib, those are two different objects. This is sometimes a tricky thing about nibs: it's really convenient to have instances automatically created for you, but it also means some fiddling around with references when you want to do things across nibs.
It sounds like you put instances of WarehouseView and WarehouseDetailView into both your individual nibs and MainMenu.nib and expected them to be the same objects. It won't be so. You have to link objects in the nibs to objects that they already know about. You'll have to work this out for your particular situation.
I don't know where your model is stored, or how you're getting the nib loaded. Whichever object it doing that loading, though, will likely be your link between the individual nib and the rest of the app. This is what the File's Owner proxy object in nibs is for -- it gives you a place to hook up objects in the nib to code that they wouldn't otherwise know about.
*: If you find it easier to layout the views if they are not enclosed in the split view in IB, you could set them up on their own: put the custom view objects in the MainMenu.xib window and you can open each view in its own IB window (though it will not be in a window in the app). Then set the split view's subviews in something's awakeFromNib.

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...

Resources