UITableviewController losing reference to tableview - iphone

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;

Related

Objective-c - Getting objects from XIB file into a view controller

So I have a XIB file, which contains a view. In that view, I want to add custom objects and then being able to get those objects, and use them in a view controller I have where I crate other things programmatically.
My XIB file is called "MyXibLibrary.xib"
My view controller where I want the objects to be added to is called "ContactDetailsViewController"
My view controller is being pushed from a UITableViewController like this:
ContactDetailsViewController *detailViewController = [[ContactDetailsViewController alloc] init];
And inside my ContactDetailsViewController viewWillAppear I have this code to get the XIB objects:
UIView *xibView = [[[NSBundle mainBundle] loadNibNamed:#"MyLib" owner:self options:nil] objectAtIndex:0];
[self.view addSubview:xibView];
Now, a for instance, the loadNibNamed property should be? Name of the XIB file? Name of the view in that XIB file? Or what?
All this is bringing me errors and the app trows exeption.
I have no clue what so ever on how to work with XIB files since I super new to Objective-c coding.
Any help would be really appreciated!!!
Thanks!
The XIB, which is referred to as a NIB (as a matter of history), defines at least one view that is to be "controlled" by a view controller. This view can represent the whole user interface or simply a subview of another view (e.g. your XIB could represent a reusable table row). Thus, you should not be using a XIB as a sort of container for pre-built interface elements in the manner you describe.
However, it is simple to work with the components of the XIB provided your controller knows about them. That is, the elements of your XIB should connect to properties of your view controller class.
For example, let's say you have the following view controller interface:
#import <UIKit/UIKit.h>
interface MyViewController : UIViewController {
}
#property (strong, nonatomic) IBOutlet UITextView *textEntry;
#property (strong, nonatomic) IBOutlet UIButton *enterButton;
A corresponding NIB would be named MyView.xib. In the interface builder, you would set the "File's Owner" for the NIB to be "MyViewController". You would then link the interface elements, a UITextView and a UIButton, to MyViewController's properties (in whatever method you prefer - usually an option+click & drag from the interface element to the File's Owner object).
Having done this, you can then instantiate the view controller anywhere you please and work with the properties of that object. For example, let's pretend this code is in a file named "SomeOtherController.m":
- (void)aMethodOfSomeOtherController
{
MyViewController *myView = [[MyViewController alloc]
initWithNibName:#"MyViewController"
bundle:nibBundleOrNil];
NSString *buttonLabelText = [[[myView] enterButton] titleLabel] text];
NSLog(#"Button label text = %#", buttonLabelText);
[myView release];
}
When this method is invoked, an instance of MyViewController will be created which will automatically load the stored objects from the NIB and bind them to the view controller object's properties. It will then retrieve the text of the button's label and write it to the log console.
If you want to load an UIView from NIB, this code would be more correct (since you don't know the index of a needed object in the xib file).
- (id)loadViewFromNIB:(NSString *)nibName owner:(id)owner class:(Class)_class
{
NSArray *objects = [[NSBundle mainBundle] loadNibNamed:nibName owner:owner options:nil];
for (id object in objects) {
if ([object isKindOfClass:_class]) {
return object;
}
}
}
If you look at the documentation for UIViewController, there's a method called initWithNibName:bundle:. It lists five different sample code projects that Apple provides to demonstrate how to use xib files and view controllers. You should read a few of those to get a basic understanding.
Open MyLib.xib in interface builder and check that you actually have a UIView component in that file.
What error message do you get from the exception?

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.

UI Elements and IBOutlet Variables in Storyboard when instantiated recursively?

What I've done so far:
I am using xcode 4.2. I created a UITableView which contains an ImageView. The UITableView uses the class MyTableViewController which has the files MyTableViewController.m/.h. I created an IBOutlet variable called _bgimageview. Then in the storyboard, in the connections inspector, i connected the ImageView to this _bgimageview variable. In my viewDidLoad function of MyTableviewController.m, I set a backgound image to the _bgimageview. When I run the simulator, click on a few tabs to get to MyTableViewController, and hten I see the background image. Things work great so far.
The problem
I've also successfully built a recursive tree, but the problem is that I lose the backgorund image after the root level of the tree. I think i know why, but don't know how to fix. I instantiate a new MyTableViewController on each row-click like so:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
MyTableViewController *childView = [[MyTableViewController alloc] init];
childView._menu = children; // an NSDictionary of children
[self.navigationController pushViewController:childView animated:YES];
}
As mentioned previously, I populate the IBOutlet variable for the backgruond image in the viewDidLoad function. But that IBOutlet variable is linked up to the ImageView via the Storyboard connection. In tree levels below the root level, I programmatically instantiate new MyTableViewControllers and thus, I'm probably losing the relationship between the IBOutlet variable for the backgund image and the actual UIImageView mentioned in the Storyboard.
Can someone re-assure me this is the problem and how I might go about adding a backgorund image to MyTableViewController when used in a hierarchical manner?
MyTableViewController *childView = [[MyTableViewController alloc] init];
This line creates a new instance of your view controller without reference to the storyboard. It will therefore not be connecting any of your outlets - the table view will probably be OK, since that is created and connected by default, but anything else will not be connected.
You can confirm this by logging your image view outlet in viewDidLoad - it will be nil.
You should create a recursive stack by dragging a segue from the row of the table down to the view controller object of the same view controller:
As Lvsti points out in comments, you can pass any parameters across in prepareForSegue:sender:

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.

Subclassing UITableViewController what you get?

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.