Associating a UITableView with a TableViewController - objective-c

Can anyone describe how it is possible to have a TableViewController with its xib file having a at its root and the uitableview as a subview?
I believe the TVController somehow assumes that UITableView will fill the entire area.
Why is that?
I have a really specific need to build a kind of side and bottom tabbed interface with a UITableView as its main area. Pressing tabs changes the predicate for the fetchedresultscontroller etc etc.
The reason I want this is because of the breadth and depth of the data categories in the data model. I rally need to flatten the menu structure a lot...other wise with a table and navbar controller structure, user experience will be akin to sinking to ever deeper depths of a cavern!
My idea is tried and true in other paradigms...in iOS it almost looks like it's Apple's way or the highway. I am OK with APPLE of course no gripe.
But I really would like to create this.
I tried adding a new tableviewcontroller complete with xib and then removing the UITableView in IB and replacing with a UIView and a UITableView as a subview, hooking up (I believe) the delegate to the file's owner.
I created an IV tableView for when I want to reference it and again used IB to hook it up in IB
Try to run it and it whines that...
[UITableViewController loadView] loaded the "TabbedTableController" nib but didn't get a UITableView.'
Really can't seem to get my head around what the issue is here.
There doesn't appear to be anymore I can do to hook the UITableView up!
Any help would be terrific. I'll send you a Christmas card in desperation :^)
Also...why should it be so and how strict is this UITableView fullscreen thing?
Enlighten me if you can. The docs I have read don't want to.
Regards
Keith

A UITableViewController does assume that the root view (i.e. the controller's view property) will be a UITableView, thus the table view fills the screen. When you need a view that combines UITableView with other top level views, you will need to do a little more work but it's not hard:
Your view controller will not subclass UITableView. Instead, do this:
#interface MyViewController : UIViewController
<UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, weak) IBOutlet UITableView* tableView;
In Interface Builder, drop in a UITableView and whatever other controls you need. The table view can be any size and in any location in the view hierarchy. Also in Interface Builder, ctrl-drag from the table view to your VC and set the delegate and dataSource outlets, and ctrl-drag from your VC to the table view to set the tableView outlet.
Your view controller implementation should be the typical table view controller implementation: cellForRowAtIndexPath, etc.
A UITableViewController is more or less just all of the above work packaged up into a single unit for you.

Related

Why I can't drag outlets from a custom UIView Class?

I have a TableViewController With a dynamic cell and a view I added above it.
I've created a UIView class and added it as a custom class for that view ( just like I do with a custom cell) but I can't drag labels etc from that UIView to its .h file. Only to the main TableViewController.h file. Any idea what's the problem?
A table view in a UITableViewController takes up the whole screen, so the view you added is actually in the table view, not above it, so that's why you can connect to the table view controller. If you want to add a view above the table, use a UIViewController instead, and resize the table view so it doesn't take up the whole screen.
I've noticed this too (for an OS X project) in Interface Builder. I'm not sure if it is a bug or not in IB.
What you will have to do is enter the #property declarations in your .h file manually and then you will be able to connect them.

Change a UIViewController to a UITableViewController inside a storyboard?

I've made a view in my storyboard which I've now decided I'd rather display its data via static table cells.
I can't use static table views in a UIViewController (Static table views are only valid when embedded in UITableViewController instances). So, I need to convert my existing UIViewController to a UITableViewController somehow. I've changed the .h file's parent, but that hasn't done it.
Is there another way to get this going? I'd really rather not have to make a new VC in the storyboard and move everything over, it's a big hassle.
I'll add to this, since the question is about how to change a UIViewController into a UITableViewController, and given that this question is over a year old and the original answer, while valid and may or may not have been the only solution at the time, doesn't actually answer the question and is not the only solution.
It IS possible to do this, you just have to set up the table view delegate and datasource outlets in IB, and manually edit the storyboard XML, which sounds scary but is actually very easy.
First, change your class's parent to be a UITableViewController. UITableViewController already adopts the UITableViewDatasource and UITableViewDelegate protocols, so if your class does too you can remove them:
#implementation MyTableViewController : UITableViewController
...
#end
Next, create new referencing outlets on your UITableView for its dataSource and delegate. The easiest way to do this is to control-drag from the UITableView to itself. The popup will give you the dataSource and delegate options.
Lastly, you need to change the storyboard XML. The storyboard file can get pretty big pretty fast. The easiest way to find the scene you are looking for is by setting Storyboard Identifier in the Identity Inspector. To view the XML directly, right click on the storyboard file in the project navigator and select "Open As -> Source Code". Now just search for whatever you set the reuse identifier to earlier. You'll see something similar to this:
<!-- My Table View Controller -->
<scene sceneID="EuE-XX-cCb">
<objects>
<viewController storyboardIdentifier="MY_TABLE_VIEW_IDENTIFIER" ... >
// Lots of other stuff
</viewController>
</objects>
</scene>
All you need to do is change the opening and closing view controller tags
<viewController>
</viewController>
to be tableViewController instead
<tableViewController>
</tableViewController>
That's it! No need to create a new UITableViewController scene or embed a UITableViewController in a container view.
EDIT:
I should also add that the UITableView MUST be the root view. It cannot be embedded inside another UIView.
If you want your static cell table view not to take up the entire screen, then using a container view is the easiest way to go. Start with a regular UIViewController and drag a container view (next to normal UIView in the object list) into its view. Resize it however you want -- the storyboard will automatically provide a view controller connected to this container view with an embed segue. Delete that controller, drag out a table view controller and right-drag from the container view to this table view controller to make a new embed segue. This table view controller can be accessed from the UIViewController with its childViewControllers property (and conversely, you can access the UIViewController from the table view controller with parentViewController if you need to).
What I did, is creating a UITableViewController in IB, open the Storyboard with a text editor, and copy all the nodes inside from the UIViewController to the UITableViewController.
I think that with this way there's less risk of deleting something important.
Before copying the sections objects, make sure that both tableviews (UIViewController and UITableViewController) have the same properties set like: static or dynamic cells, style (plain or grouped), etc.

Can I load nib contents in to UIView using only Interface Builder?

Does anyone know a way to, in a storyboard, load a UIView's contents from another nib? I know I can do this easily with code, but I am trying to figure out how to do more in IB.
I have a storyboard with my main UI layout, I have a UIScrollView and I want to design its contents in IB. The only way I could figure out how to do this was to design the UIView in its own .nib, but then my issue is, how do I load the nib without coding it to do so? Is this even possible? It doesn't seem too far fetched to me.
I'm assuming you simply want to lay out your UIScrollView in IB, that a .nib is mentioned because that was an approach you were exploring, but if you could do this strictly in your storyboard that would be acceptable, if not preferable:
First, create a new file in Xcode that is a subclass of UIScrollView.
In your storyboard, drag a UIScrollView out to the scene (viewcontroller) where you want to display this scroll view.
In the Identity inspector, set the Custom Class of the UIScrollView to your subclass of UIScrollView.
Create an outlet for this UIScrollView by ctrl+dragging the UIScrollView into the .h file of the ViewController subclass it's displayed in. Name it something like myScrollView
In your ViewController's -viewDidLoad method, set the contentSize property of the UIScrollView to whatever size you want it to be. So it will look something like:
self.myScrollView.contentSize = CGSizeMake(800,800);
Now, drag out UI objects to your UIScrollView and design.
IMPORTANT: To create outlets to these objects is a little tricky. Let's say you've dragged out a UILabel. You need to manually go into your UIScrollView subclass and add to the .h
#property (nonatomic, weak) IBOutlet UILabel* myLabel;
and to the .m
#synthesize myLabel = _myLabel;
Now you need to get your outline view on screen along with your storyboard and ctrl+drag FROM YOUR SCROLL VIEW TO YOUR LABEL to create an outlet. This is kind of the reverse of what you're used to.
Now you can reference that outlet from within the viewcontroller or the scrollview subclass . For instance, in the viewcontroller -viewDidLoad you could say:
self.scrollView.myLabel.text = #"Hello World";
HTH!
If what you want is to edit inside a scrollview from IB, it's a pain, but doable.
Have a look at my answer on this question.
Add a generic UIView in the IB, setting its custom class to the name of your nib file.
Replace GradientControl with the name of your nib file (minus the '.xib').

Objective-C / iOS: Subclassing UITableViewController for a custom view

As we all know, table views in Cocoa Touch are one of the niftiest pieces of framework elements that's out there. As a convenience, Apple gave us a nice view controller class to encapsulate the functionality of a table view in a vc, the UITableViewController.
At the same time, there are times that we want to utilize the functionality of a table view without having it take up the whole screen. However, there seems to be no way to do this by subclassing UITableViewController. Instead, I had to hookup a table view and manually subscribe to the UITableViewDelegate and UITableViewDataSource. If I try to subclass UITableViewController, my app crashes before it can even put the view on-screen...
My question is, is there something I'm missing? When subclassing UITableViewController, I hook up my custom table view to the tableView property in UITableViewController. Is there something else I have to do?
UITableViewController only adds minor conveniences over UIViewController: it creates and positions the table view, hooks up the delegate & datasource (to itself, generally), passes the view controller editing property through to the table, and does a couple of useful UI bits when the view appears. (See [the docs][1] for details.)
Just about all of the above are either A) things that you're needing to change in order to have a non-fullscreen table, or B) things that you can do in a line or two each, and which UITableViewController only does for your convenience. For cases like this, you're better off using your own UIViewController subclass.
Step 1: Subclass UIViewController instead of UITableViewController
MyTableViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
Step 2: Use interface builder to drop a tableView and custom View
Step 3: Declare the tableView property as IBOutlet in your MyTableViewController header file and bind it to the tableView in the interface builder
IMHO, This process would give you more flexibility.

How do you hook up IBOutlets across scenes in the Interface Builder storyboard?

I have a custom UITableViewController with 2 properties:
#property (strong, nonatomic) IBOutlet VenueHeaderViewController *header;
#property (strong, nonatomic) IBOutlet VenueFooterViewController *footer;
The UIViews of my VenueHeaderViewController and VenueFooterViewController were designed in IB. Each of these controllers has IBOutlets to its subviews as set up in the storyboard. This is my storyboard:
My question is, how do I now connect my header and footer IBOutlets inside my UITableViewController to instances of my VenueHeaderViewController and VenueFooterViewController while retaining the layout and IBOutlets which I have set up in the storyboard?
You can't hook up IBOutlets across different scenes in a storyboard. Scenes are each entirely self-contained, and only connected via segues (or relationships in the case of special container view controllers like tab, navigation, split view and popover controllers). If you've done any IB work without storyboards, think of each scene (view controller) as being in its own nib (in fact, that's what storyboards do behind the scenes).
Beyond that, it's generally the case (on iPhone at least) that there's a one-to-one mapping between a view controller and a "screen" of UI -- you generally don't have different view controllers managing different parts of the screen, as appears to be the case with the header, table, and footer you have. (Thus, you'll pretty much never have an IBOutlet to any UIViewController subclass.)
So what can you do? Here's a few different approaches, from easier to harder:
UITableView header & footer
If you're meaning to assign those header & footer views to the UITableView's tableHeaderView and tableFooterView properties, you can do that in the storyboard in IB -- just drag a UIView of some sort from the library toward the top or the bottom of the table until you see a blue line above or below the prototype cell(s):
The table header & footer views might or might not be what you're after, though: they're part of the scrolling content of the table (that is, they appear above the first row and below the last, respectively, so they can be scrolled off the screen).
Views above & below
If your intended use of these views is as "header" and "footer" in that they always appear above or below the table regardless of where it's scrolled, then what you really need is to have the header, footer and the table view all be subviews of a root view.
For that, you'll need a regular UIViewController subclass rather than a UITableViewController subclass. You can put a UITableView in as a subview of that view controller's root view, and arrange whatever other views you want to be visible above/below it. (Just make sure to set the autoresizing sensibly if you plan to support rotation.) Here's an example:
(If you're wondering where the prototype cells are when you first drag out the table view, check the inspector -- you set the number of them in the upper right of that screenshot.)
Top level views
With regular nibs (not storyboards), you can set up views in IB which aren't the view controller's root view. Then you can still connect outlets to them, and programmatically insert them into the view hierarchy as needed.
You can sort of do this in a storyboard, too -- drag views to the black bar beneath the scene -- but due to a bug in the current version of Xcode, you can't see these views for editing. Oops.
Multiple view controllers, really
If none of the above suit your needs, you might still have a use for multiple view controllers -- say, if you wanted to switch out different different header views at various times, and save memory by dynamically instantiating these view hierarchies as needed. Cases like this are pretty rare, though... you should make sure you've exhausted other options first.
In effect, you're still using one of the previous two approaches, but the views you want are located in other scenes (again, it's like they're in other nibs). Here, the view controllers holding the other views don't even need to be custom subclasses of UIViewController, since they're just temporary containers for views you want to insert into a different view controller's view hierarchy.
In that case, the storyboard you have is what you want... it's just a matter of getting those view controllers appropriately loaded, which you can do thusly:
SpecialViewController *svc = [storyboard instantiateViewControllerWithIdentifier:#"SpecialViewController"];
Then, pull the view property from each view controller, insert it into your "main" view controller's view hierarchy, and dispose of the the view controller you pulled it from.