Subclassing UITableViewController what you get? - iphone

This is probably me being a little dim, I am setting up a UITableViewController via a UINavigationController, I have subclassed UITableViewController: (see below) and have implemented the datasource methods to get my table up and running
#interface RootViewController : UITableViewController {
NSArray *dataList;
}
#property(nonatomic, retain) NSArray *dataList;
#end
My question is: when I came to implement the viewDidLoad for RootViewController I wanted to set the title for the table (See image below). I looked at the docs for UITableViewController and found that it had a property called "tableView" so I tried ...
[[self tableView] setTitle:#"Eeek!"];
This did not work, what I should have tried was ...
[self setTitle:#"Eeek!"];
What I am wondering, when you subclass UITableViewController and add code your actually dealing with the tableView and not the UITableViewController, does this make sense?
Gary

what you are setting is actually the UIViewController (the parent class of UITableViewController) title, which is what UINavigationController uses to display a title in its navigationBar (the blue bar in your image)
Edit to better answer question: so no, when you subclass UITableViewController, you are actually dealing with the controller, not the table view itself.

Short answer to the question, no - you are still dealing with the properties of the Controller. The difference between the two setTitle: operations is:
// This message is being sent to the UITableViewController
[self setTitle:#"Eeek!"];
// This message is being sent to the UITableView property of the UITableViewController
[[self tableView] setTitle:#"Eeek!"];
There is no setTitle: method on the UITableView object, so that fails.
Abstractly in terms of MVC, the first is setting the property on a Controller and the second is setting the property on a View.

Related

UITableViewController inside UIViewController

I'm working on an Iphone project. In the storyboard I have myViewController containing few UILabels and a UITableView.
The mentioned UITableView is referenced in the myViewController class by an IBOutlet :
IBOutlet UITableView *myTable;
Now I build a UITableViewController (myTableViewController) that I want to populate myTable.
Then I go back to myViewController and I allocate in here myTableViewController :
MyTableViewController *myTableViewController = [[MyTableViewController alloc] init];
myTableViewController.tableView = myTable;
myTableViewController.tableView.delegate = myTableViewController;
myTableViewController.tableView.dataSource = myTableViewController;
It is not working (EXC_BAD_ACCESS error).
Usually I should populate myTable trough the UIViewController (making sure it conforms to nedeed protocols). But I'm really wondering If I can do what I did right above..
Most cases you can solve this by creating a UIViewController and a reference to the table inside the ViewController using an IBOutlet. However, there are cases where you need a full blown UITableViewController, such as in core data, and you also would like the ability to add things like UIToolbars. I know, a lot of times you can hack a UINavigationController, but sometimes you don't want a hierarchy/stack. In such a case, admittedly fairly rare, one way to do this is to create a UITableViewController subclass. You can import and initialize it in your UIViewController class, create an outlet from the tableView sitting inside the UIViewController's nib/scene, and then assign the tableView property of the UITableViewController to the tableView outlet of the UIViewController.
self.instanceOfUITableVC.table = self.tableView
It's a bit complex, but it works. Now you can control the tableView using the UITableViewController subclass instance.

UITableviewController losing reference to tableview

I have been working on this for 2 days now, cant seem to get a grasp. I'm missing something very basic I guess.
Here's what I have:
A UIViewController as the Apps root controller.
There's a ContainerView, a subclass of UIView which I add to my root controller view.
Within that I want a UITableView.
Since there are several different Containers, I have different Nibs for each.
Heres how its wired: Nib with content, has the container as its file's owner. There's an outlet to the UITableView, it has the container as source and delegate.
The container implements the protocol methods.
Now I can't call reloaddata on the UITableView since it's nil. I type po in the consolo and it says 0x0 but I don't know why.
I have been trying different approaches, but all ended up in losing the reference to the tableView.
It's not like it's my first tableview I create but I have no clue on what I'm doing wrong here.
Any HELP please!!!!
Code:
This is my Outlet:
IBOutlet UITableView *contactsTV;
File's owner has a connection to it, the tableview vice versa.
I create the nib by doing:
Contentview *v = [[Contentview alloc] initWithFrame:[[contentViewArray objectAtIndex:i] CGRectValue]];
while contentViewArray is some array storing Framevalues as strings.
Then I do:
[v prepareView];
and it looks like this:
- (void) prepareView {
NSArray *mediaPlayerViews = [[NSBundle mainBundle] loadNibNamed:#"MyView"
owner:self
options:nil];
UIView *v = (UIView *)[mediaPlayerViews objectAtIndex:0];
[self addSubview:v];
}
Just experienced a similar issue -- everything appeared wired up correctly (Xcode 4) but the outlet reference was nil.
When I created the file, I used the "New File" -> subclass of UITableViewController. with NIB (automatic) process to set up the file. This resulted in the controller being declared as a UITableViewController and the NIB had a UITableView as it's root.
Although the TableDataSource and TableDelegate methods got called as expected, the outlet for the TableView was never being set when the nib was loaded.
To fix this, I basically had to change the controller from being a subclass of UITableViewController to just UIViewController and set the NIB accordingly: I cleared the NIB, added a UIView with a UITableView as a child, reconnected the outlets (View, TableView, TableDataSource, and TableDelegate), and it all worked as planned.
I think this may be a bug with XCode, when creating a subclass of UITableView with NIB.
Set it as a UITableViewController it should work.
Do you have property set in header file along with
IBOutlet UITableView *contactsTV
?
If you don't have setter method for your contactsTV, then your contactsTV isn't retained by your object.
Try to replace your code with
//header file
UITableView *contactsTV;
#property(nonatomic, retain) IBOutlet UITableView *contactsTV;
//implementation file
#synthesize contactsTV;

iPhone Subclassing view controller and IBOutlet UITableView

I have the following problem. I've created a ViewController pretty much like the above
#interface MyViewController : UIViewController {
IBOutlet UITableView *myTableView;
}
#property (nonatomic, retain) IBOutlet UITableView *myTableView;
I've linked myTableView on the Interface Builder to the matching nib's UITableView. and I've subclassed MyViewController to create YourViewController as so:
#interface YourViewController : MyViewController {
}
And then I load from a TabBarController the YourViewController on a tab item. Although I can see that MyViewController is indeed invoked at the end, no table view is displayed on the emulator.
I've tried debugging the MyViewController and it appears the the IBOutlet is nil.
Why is that?
I have encountered major issues with inheritance and IBOutlets and IBAction. I advise you to avoid that, and create shared stuff in another way.
I was hit hard by bugs when getting memory warnings for instance. Outlets and actions didn't get reconnected properly when they were defined in base class vs derived class.
Probably MyViewController's nib file is not loaded at all. Are you using for YourViewController a specific nib file? and in which way are you creating YourViewController.
Can you also try to define an "awakeFromNib" method in YourViewController and then from it call [super awakeFromNib] ?
However to understand your issue you must clearly explain how you load objects and if and where you use Nibs?
If you add it dynamically using code then only it will work. Not using Nib.
the UITableView (ie. your myTableView) needs delegates for data source and and its control.
And your controller needs a link to the Table view in the xib.
declare table delegate protocols in the interface section of your controller.
using IB, link the TableView in your xib to owners file:delegates.
using IB, link the file owner myTableView to the tableView in the xib.
I hope it will help.
Assuming that you have your whole navigation stack in MainWindow.xib
Open MainWindow.xib
Select YourViewController (Or whatever your controller that is subclassing UITableViewController is called)
Select Attributes Inspector
Ensure that the 'NIB Name' property has your correct YourViewController (Or whatever the name) selected
I had this exact same issue, this solved it for me.

iPad UISplitViewController multiple root views

I am developing for iPad and have created a standard UISplitViewController application using the template provided in Xcode - a standard UITableView on the left and a detail view on the right.
I have modified the template so that when a user selects a table cell from the left view it pushes a new table view in it's place (still on the left side). This works without issue, but I would like to be able to update the existing detail view from the new table view - kinda like how Apple's Mail application works.
- I am not trying to create multiple views on the detail view (right hand side) - I've read the documentation and seen the sample code provided by Apple.
I read/followed many tutorials, but can't seem to get this relatively simple view hierarchy to work.
More detail:-
Using detailViewController.detailItem = #"Test"; in the RootView didSelectTableRowAtIndexPath delegate method updates the Detail view label. Using the exact same code in the newly pushed Table View does not update the label - am I missing a reference point or something??
Since posting I've tried to use protocols & delegates to update a label on the detail view. The label updates correctly when changed from the Root View using the new methods, however, when I push a new view onto the root view (left hand side) I can no longer update the label.
At some point after creating the RootViewController (or maybe even in a custom init method) you are setting the delegate for the DetailViewController, its a common mistake that when a new rootViewController is pushed onto the NavController that you forget to set the delgate again.
You probably are creating a new controller in the:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
method and recording/incrementing the level of the new controller before you push it onto the navController. After you create this new controller, set the delegate again.
newRootController.myDelegate = self.myDelegate;
Before you do this If you NSLog the delegate just before you use it, you will probably find its nil.
Try the viewControllers property of your UISplitViewController
#property(nonatomic, copy) NSArray
*viewControllers Discussion The array in this property must contain exactly
two view controllers. The view
controllers are presented
left-to-right in the split view
interface when it is in a landscape
orientation. Thus, the view controller
at index 0 is displayed on the left
side and the view controller at index
1 is displayed on the right side of
the interface.
The first view controller in this
array is typically hidden when the
device is in a portrait orientation.
Assign a delegate object to the
receiver if you want to coordinate the
display of this view controller using
a popover.
Please beware of the detailViewController! You have to pass this instance variable to your new root view. So something like this:
newRootViewController.detailViewController = self.detailViewController
Otherwise your new root view will never know about the detailView. For your new root(table)view you have to do things like:
#import <UIKit/UIKit.h>
#class DetailViewController;
#interface VorhersageTable : UIViewController {
UITableView *vorhersageTableView;
DetailViewController *detailViewController;
}
#property (nonatomic, retain) IBOutlet UITableView *vorhersageTableView;
#property (nonatomic, retain) DetailViewController *detailViewController;
#end
to declare the property of the detailViewController in your new class.
Add this in your RootViewController.didselectRow, before you push the second table (e.g SubRoot)
SubRoot *subController = [[SubRoot alloc] initWithNibName:#"SubRoot" bundle:nil];
subController.detailViewController = self.detailViewController;
And create the SubRoot.h and SubRoot.m similar to RootViewController.
#class DetailViewController;
#interface SubRoot : UITableViewController {
DetailViewController *detailViewController;
}
#property (nonatomic, retain) DetailViewController *detailViewController;
#end
then synthesize detailViewController.
Hope it helps.

What is the easiest way to add a row in a UITableView with a user-provided string?

I have a simple UITableViewController in a UINavigationController that displays a list of strings from an array with the default Edit/Done button on the right-hand side of the navigation bar.
When pressing the Edit button, the UITableView animates correctly and shows the red minus icons to delete. Pressing the delete button removes the row from the table view and the array (implemented in the tableView:commitEditingStyle:forRowAtIndexPath: method of the UITableViewController).
I would now like to allow the user to add a row to the view (and add the string to the underlying array), but I'm not sure how to go about doing so. The commitEditingStyle method has else if (editingStyle == UITableViewCellEditingStyleInsert), but I don't know how I can get the user to input the string.
I've read the Table View Programming Guide (more specifically the example of adding a table-view row), but this seems to require a whole new UIViewController subclass just to get a string from the user.
Is there no easier way?
Creating another view controller is probably going to be the easiest way in the long run. You can present it modally by calling
SomeViewController* theViewController = [[SomeViewController alloc] init];
[self presentModalViewController: theViewController animated: YES];
[theViewController release];
When the theViewController is ready to go away it can call
[[self parentViewController] dismissModalViewControllerAnimated: YES];
OR
you can setup a protocol for your new view controller so it can notify your original view controller of completion and send a value back, if you wanted an NSString back you might use
#protocol MyViewControllerDelegate
- (void)myViewControllerDelegate: (MyViewController*)myViewController didFinishWithValue: (NSString*)theString;
#end
MyViewController would then have a delegate property
#interface MyViewController
{
id<MyViewControllerDelegate> delegate;
}
#property(nonatomic,assign) id<MyViewControllerDelegate> delegate;
#end
If you use the protocol method your original view controller will adopt that protocol and will dismiss the modal view itself when it receives this message.
I hope that helps out, it may seem a little complicated at first, but it makes gathering data very easy.
You could use a UIAlertView or similar class yourself. Just pop up the modal view to request the string, establish the right callbacks, then pop it in your dataSource.
You can also insert a cell with a UITextView and a "Tap to Edit" placeholder, then on the textView Callbacks, remove the textView and display the string. Further editing would need to drill down or do something else