How do you make a view corresponding to a model subclass that holds view elements corresponding to the parent model class? - objective-c

I have some UI elements that will share common parts with other UI elements. They correspond to model objects in an inheritance hierarchy.
As an example let's say all Layers can be toggled on/off. All WaveLayers are Layers which additionally define a .wav filename. And there is a specific concrete subclass of WaveLayer called GroovyLayer which requires additional parameters.
Visually I'd like to have a long panel where the top section holds the general Layer UI, the next section holds the WaveLayer-specific UI, and the last section holds the GroovyLayer-specific UI. There may be like 10 or so concrete subclasses, each which share the same top sections corresponding to Layer and WaveLayer.
How should I set this up in InterfaceBuilder? Do I start at the top (with a placeholder for the subclass stuff) or at the bottom (with placeholders for the parent classes' stuff)? How should I go about setting up these placeholders in InterfaceBuilder and substituting in the right NSViews at the right times?
I've got this sort of thing to work by using a blank "custom view" in IB and tying it to an outlet in my controller class, and then substituting that view with another view tied to my controller from elsewhere in another NIB, but that seems unelegant, as my controller then carries both "old view" and "new view" members...

Lay out the views however you wish. Then select the custom view that represents your subclass and set its class name in the inspector.
As to whether to load the views from separate xib files, I think that's overkill here. From your description these views are always visible together, so you gain nothing but complexity loading them from individual files.
The trick you seemed to be missing was setting the class name of the custom view to that of your subclass.

Related

Cocoa binding search field to tableview in a different nib

I've got a user interface that looks pretty much like iTunes. For purposes of encapsulation, the top area and the main table view are in separate classes with separate nibs. I want to bind the search field from the top view controller to the tableview in the bottom view controller. I've arranged it so there are properties to store the NSArrayController in both classes. The array controller is an array of dictionaries, and the dictionaries have a "search_keywords" key that I want to use to filter the tableview.
Is it possible to set up the search stuff in Interface Builder even though it's in a separate nib? I can't figure out what to put in the various boxes.
If it's not possible with IB, I assume it's possible in code, since there is a view controller with references to both of the sub-view controllers and I can get at the search field, table view and array controller objects through properties on the two classes.
How do I set it up? IB would be best, if it's possible.
What I did was use the NSSearchField in the top view controller as a dummy/placeholder. I create the "real" search field in the tableview's nib, and wire up all the bindings stuff as per normal. Then in the main view controller I grab the search field out of the tableview's nib, and replace the dummy searchfield with the real one using replaceSubview:with:
Now I can continue to use IB to modify the bindings, and it doesn't really matter what's in what nib as it all gets placed properly in the view hierarchy at runtime.
In your concept you cannot bind the search field in IB in the desired way.
Do it like
1. Create an accessor-method (accessorMethodForTextInSearchField or what name you want to use) in the TopClass for the Text in the searchField
2. Import the TopClass.h in the MainClass
3. In MainClass you can use
NSString *searchString = [ NSString stringWithString:[ TopClass accessorMethodForTextInSearchField] ];
4. Now search for searchString in the array

Sharing code between a UITableView and a UICollectionView

My iPad and iPhone interfaces use a UICollectionView and a UITableView respectively. In each case, there is a lot of commonality:
each has the same number of sections (hard-coded)
each section has the same number of respective rows/items (derived from the same data source)
each has identical cell content (these are custom views built using auto layout so are suitable for both cases)
each has identical section headers and footers (again, custom content)
each can respond to certain notifications in the same way (e.g. when new data is received, refresh the data source) but with custom parts also (reload the UITableView vs reload the UICollectionView)
each will present the same controllers via cell selection, though the UITableView will push the new controller and the UICollectionView will use a popover.
I am using a shared parent class to cater to some of this. This approach seems especially well suited to the data requirements - the parent class builds the data and is responsible for maintaining it. I use two subclasses to present the data - one with a UITableView and the other UICollectionView.
The presentation side is a little less clean. To take the simplest example, when the table/collection view needs to know the number of sections, in each case I am relying on a customized method in the parent:
return [super sectionsCount]
This allows me to set many values only once and have both views updated.
Then comes the part that is working poorest. Again, to simplify, consider the header view for the first section. In both cases, this should be identical. I have a custom UIView subclass that I want to use, with a couple of properties that will be set the same. The problem here is that the re-usable header for a table view section expects a UITableViewHeaderFooterView and the counterpart for a collection view expects a UICollectionReusableView. So to accommodate this, I'm having to create subclasses of these simply to hold the header view I want in both. So in summary:
What I want: UITableView and UICollectionView should use the same UIView subclass as the header for section. The custom properties of that view should be set identically in each case.
What I am having to do:
Build the required UIView subclass for the header.
Build a UITableViewHeaderFooterView subclass that holds one such header. It's init does nothing more than add a header view.
Build a UICollectionReusableView subclass that equally does nothing more than add a header view.
When the collection view needs a header, create an instance of the UITableViewHeaderFooterView subclass. Set its properties.
When the table view needs a header, create an instance of the UITableViewHeaderFooterView subclass. Set its properties.
Once I have to do this for footers, and especially cells, things are getting kinda icky. I have three times the classes I should need, and I'm repeating all of my code for setting custom properties of the view.
How can I best re-use this logic between the UICollectionView and UITableView?
You can just create stock UICollectionReusableViews, UITableViewHeaderFooterViews, etc. and add your custom view as a subview. If you need to access the custom view later, you can set its tag property and use [view viewWithTag:].

Nib vs. View - How do they interact/overlap each other?

I'm very new to objective-c and it seems my question is so basic there's nothing concise on it around (I just end up more confused by reading things).
When you create a .xib file, you link it to a controller (usually, I think). At the same time, you can do things you can do in .xib by defining views in code. I thought I understood part of it when I realized most of the items you drag onto a .xib are view objects. I guessed from there that .xib were somehow just representing real code for views. Is that accurate? Or am I completely wrong? I really have no idea.
Xib files do not represent real code for views, only the structure of the view's data. Each xib (or a storyboard) has enough information to do all of the following:
Instantiate elements of the view
Set properties of individual elements of the view
Connect elements of the view in a hierarchy
Connect "outlets" of objects in the Nib to properties or variables of views in your code.
However, there is no "real code" there, only the metadata. Cocoa has enough smarts to build and connect the objects, but the actual code is always in your .m files.
A view controller manages a view which is made up of many subviews. While, every view can have only one superview at most. ( superview is nil for the top-most view). This is called the view hierarchy.
The top level view in a hierarchy can be defined using pure code, or with Interface Builder, which produces a xib.
Its useful also to explore the relationship of view controllers to each other. Within one application window, there can also be several view controllers, each managing their own top-level view. This is called view-controller containment. An example of this is a UINavigationController or tab-bar controller. . .in more complex apps it is common to set up your own root controller that manages this aspect of controller heirarchies. (Eg swipe to reveal a navigation controller, which is under the main content cotroller).
A XIB describes arbitrary objects that conform to NSCoding but is usually used to layout a view hierarchy. So it'll be mostly UIViews, usually with a UIViewController.
However they're purely data. No code is generated. The system reads the XIBs and creates the objects purely as a data-reading exercise.
Objective-C has a fully reflective runtime — you can lookup classes by name as a string and can call methods on them the same way, without even knowing whether the method really exists in advance. Interface builders that secretly write code, such as Microsoft's in Visual C++, tend to do so because there's no way they could establish whatever you've described purely by parsing data.

How to bind nib custom view to a NSVIew subclass

I have a simple requirement.
On Click of a + button, I am trying to add a custom view to a SplitView.
I have created a class MyCustomView which is a subclass of NSView
In the applications nib file, I have a custom view which contains the buttons etc.
Now How to allocate a new MyCustomView every time ?
Is there an example to do this?
I am hoping something like
MyCustomView *v1 = [[MyCustomView alloc] init];
..
..
[splitView addSubView:v1];
[splitView addSubView:v2];
...
Please help
It's hard to tell exactly what you're describing based on your description but let's see if I understand you. You want to add a "copy" of your custom view assembly into a split view each time "+" is clicked, right?
The absolute best way to do this is to put the custom view assembly that will be copied (the "prototype") in its own xib. For each object you want to represent, you will instantiate a new copy from the xib and give it to some owner then add it to some parent view (a split view in your case ... odd for an unlimited number of views, but I don't have enough detail to say otherwise).
So. In the modern Cocoa world, such a view assembly should likely have its own view controller (NSViewController). This makes things easier for you since the xib's File's Owner will be an instance of your MyCustomViewController, whose -view is connected to the main container view in the xib (your custom view with all its subviews) and whose -representedObject is set to whatever model object your custom view represents. Your app will then maintain a list (an array or a dictionary, perhaps) of all the view controllers for the model objects. See this SO question/answer for a run-down of how to load from nibs/xibs.
This is basically how an NSCollectionView works (though the views must all be the same size - might not work for you). The collection view corresponds to your split view in this case; NSCollectionViewItem corresponds to your MyCustomViewController (and in fact on 10.5 and above NSCollectionViewItem is a subclass of NSViewController); your custom view is the collection view item's main -view. For each model object in its collection, it instantiates an NSCollectionViewItem and loads the view prototype from a xib (ideally, but this is optional), and uses this to set the item's view, then it sets the item's represented object (the model object).
I hope this clarifies things a bit. You've got some reading to do in order to understand enough of the nuts and bolts, but if you're still stuck, you might try editing your question to clarify or opening a new, more specific question.

The different of view controller and view in objective-c

I am new to Objective-c, I want to ask what is the different between view controller and view such as "UITableView" and "UITableViewController"?
What happen if I use UITableView instead of UITableViewController?
Thanks
You should look up the Model-View-Controller pattern in the Apple's documentation, since it is very important for using Cocoa. Basically, the idea in Model-View-Controller is a pattern for designing your class structure. Broadly, the model is where the application's data should be kept. The view is what controls the application's appearance and the controller is the place where the two are assembled. (Ideally, the view and the model classes do not even need to know about the other's existence).
Hence, the UITableView and UITableViewController are two different classes with two different purposes. The UITableView controls the appearance of the data and the UITableViewController "controls" the view (generally by passing it the correct data for display and layout). Since this pattern shows up again and again in Cocoa programming, you should take some time to become familiar with it.
They are two different things, they cannot be substituted for the other.
iOS follows the MVC design pattern, which stands for Model-View-Controller. The two classes you mention are 2 pieces of the overall puzzle.
The View is what gets displayed on the screen. That is its responsibility. So, the TableView is responsible for telling the phone what to render on the screen.
The View is also accompanied by the Controller. The controller decides what to do when something happens (user interaction, and other events that can happen at any time). So, the TableViewController is responsible for making the table do stuff (for example, telling the TableView what data to use for displaying on the screen).
So to sum it up, they are completely different, but they work very closely together in your application (you will almost always have 1 Controller for each View.
Well, the short answer is that one is the View and one is the Controller. Combine this with your data (the Model) and you have all the parts of MVC (Model - View - Controller).
Think of it this way, the UITableViewController controls the UITableview. They are complementary and they need each other to work.