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

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.

Related

What's the advantage of using UIViewController as owner of xib?

Most of the time, owners of xib is a UIViewController.
I sort of use it my self.
Still I am confused why.
I suppose, the viewDidLoad and viewWillAppear is kind of the main selling point.
Is that it?
What are the advantage of using UIViewController as owners of an XIB?
A UIViewController object is the main way for views to appear within an iOS window.
Apple provides this as a fundamental, foundational building block (along with so many others) which you can use to build upon quickly and get your app out to market.
And when you subclass UIViewController, you're able to do lots of beautiful customizations which can be collected and eventually turned into (hopefully decent) products. When you subclass a UIViewController, you need to set the "owner" of a XIB file to that subclassed view controller (e.g. ThioViewController), so that way the app knows what object (and user interface) is being instantiated.
Hopefully this isn't too super abstract of an explanation.
First, spend a bit time to understand MVC http://en.wikipedia.org/wiki/Model–view–controller
This is the milestone of Objective-C (not only) development.
UIViewController is controller for all your views (inside this viewController). It provide starting point for you to create views on the screen, manipulate the views, handle actions from views etc.
You can create UIViewController programmatically.
XIB is representation of the screen which you can comfortably operate in Interface Builder to create and customize design of your application screen or one of the screens.
Since XIB represent the screen(view) it must be the controller which controls all the view on the screen - UIViewController or UINavigationController or other type of controller depending of your needs.
Most of time you will subclass UIViewController and use it to achieve you goals.
UIViewController have several subclasses which inherit directly from it (UINavigationController, UITabBarController).
Also UIViewController hav several methods (some of them)
-(void)viewDidLoad
This method is called after the view controller has loaded its view hierarchy into memory. This method is called regardless of whether the view hierarchy was loaded from a nib file or created programmatically in the loadView method. You usually override this method to perform additional initialization on views that were loaded from nib files.
and
-(void)viewWillAppear:(BOOL)animated
Parameters
animated
If YES, the view is being added to the window using an animation.
Discussion
This method is called before the receiver’s view is about to be added to a view hierarchy and before any animations are configured for showing the view. You can override this method to perform custom tasks associated with displaying the view. For example, you might use this method to change the orientation or style of the status bar to coordinate with the orientation or style of the view being presented. If you override this method, you must call super at some point in your implementation.
Please check Apple documentation for more information
https://developer.apple.com/LIBRARY/IOS/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html

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.

Using a custom UITableViewController class in Storyboard

In my storyboard, I have created a new UITableViewController object for which I would like to specify some custom code. I created a new controller with the following header:
#interface CustomController : UITableViewController
When I select the UITableViewController in the Storyboard view and navigate to the Identity Inspector, I can see my CustomController in the Custom Class drop-down. However, when I select it, I hear an error sound, which is referred to as "Morse" in the system preferences.
When I deselect the UITableViewController and re-select it, it has cleared my CustomController selection and replaced it with UITableViewController. I do not understand why XCode does not accept this, as from my understanding, this is all that is required to add your own code to a UITableViewController. I am not sure if I have encountered an XCode bug or if I have configured my class incorrectly.
It is possible to use a UIViewController as a UITableViewController, but you have to do some work. If you "convert" a UIViewController to a UITableViewController, you'll need to implement the UITableViewDelegate and UITableViewDatasource protocols. You may also need to provide an outlet for a UITableView. You'll also need to handle keyboard events. Basically a bunch of effort for not much return.
Probably best in your case to start fresh with a new UIViewController class inheritted from UITableViewController.

Associating a UITableView with a TableViewController

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.

Mapkit View with tableview together

I am new to Iphone Dev, seems doesn't really understand delegate things. Could we put mapkit view and tableview together in one view?
I searched over, and someone said we can't use more than one delegate in one viewcontroller. As I know mapkit require MKMapViewDelegate and tableview require UITableViewDelegate, am I right till this point?
Then does it mean, we can't put mapkit and tableview in one view together?
The things that make me also confused, I did simple app that use textview and mapkit together. I only pass MKMapViewDelegate to view controller. But textview also require delegate to close the keypad using textFieldShouldReturn. So i manage to link the delegate from IB file, but did't pass UITextFieldDelegate to view controller. And it works.
What is the difference if we link the delegate using IB or pass the delegate param to view controller?
Thanks
A view controller CAN be a delegate for both a map view and a table view. An object becomes a delegate simple by implementing the methods of the delegate protocol, in this case that's MKMapViewDelegate and UITableViewDataSource.
An object can implement any number of protocols. You tell the compiler that instances implement a protocol by adding it to the interface:
#interface MyObject : NSObject <UITableViewDataSource, MKMapViewDelegate>
{
...
There is no significant technical difference between setting a delegate in IB and in code. I would advise setting them in IB because using IB reduces the amount of code you write therefore reducing the possibility of your code failing.