I am using the same technique as i populate my UITableView in iphone while writing my iPad application.
Tab Bar Controller >UINavigationController>UITableViewController of type myCustomTable(load From NIB)
MyCustomTableViewController NIB and class file implements the delegate methods
#interface MyCustomTableViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource> {
NSMutableArray *PDFList;
IBOutlet UITableView *PDFTable;
}
but my delegate methods are not getting called. What do i do?
Found the solution....
in the tableView delegate method
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
i was returning 0 and hence none of the delegate methods were being called.
Did you set the delegate and datasource of the table in IB? If you have, and everything is wired up, it should work.
FWIW - This is my biggest problem with nibs. If you run into problems it's much harder to ask for help from people who aren't local.
Make sure you have properly set your 'Class' in Identity Inspector (Tools -> Identity Inspector) in Interface Builder. Also set the appropriate 'Referencing Outlet' in Interface Builder.
Related
I'm using Xcode Version 5.0 (5A1413) and targeting iOS7 for iPhone. I have nothing but a UIViewController with a Table View on it. Everything I've found says to just set the table's dataSource and delegate to the ViewController. No matter what I do the app just crashes immediately. The view never loads even though there's no code written manually at all. Is it no longer possible to put a table onto a non TableViewController?
You should implement all required methods from UITableViewDataSource for preventing crash:
#required
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
I think you did a common mistake from beginners. You deleted the main view in Interface Builder and then added a Table View.
You have to know that the UIViewController class has a UIView property called view. By default this property is set to the view created with the nib (or Storyboard) file.
To say that the Table View is the main viewcontroller's view you have to right click from the file owner to the tableview and select "view".
Another method if your not comfortable yet with this method is to set the tableview in the first view.
Here is the answer - How to add static TableView to ViewController
Really you need to implement required methods.
There is no such restrictions with iOS 7.0. You can still have a UIViewController in-act as a data source and delegate for UITableView. You just need to implement all the mandatory methods set by these protocols. Could you please update your question with your code and the exception causing the crash. Without this information it would be hard to provide a solution.
I am especially interested in seeing your cellForRowAtIndexPath the way you are constructing cells and reusing them.
Add the Delegate and Datasource to the interface:
#interface MyViewController : UIViewController
<UITableViewDataSource, UITableViewDelegate>
Ok, this is really really easy, but even though I went through 100s of tutorials, I still have no idea whats wrong with my app. All I want to do is just to display a table view, even empty, but I get a black screen on the simulator and an exception in the output too.
This is what I did (followed step by step a few tutorials):
Open a view based app
This is my header:
#interface TableViewsViewController : UIViewController <UITableViewDelegate> {
IBOutlet UITableView *tblSimpleTable;
}
#property (nonatomic, retain) IBOutlet UITableView *tblSimpleTable;
#end
did not do anything in .m besides synthesizing.
IB: made 3 connections: delegate, dataSource, and tblSimpleTable to File's owner.
Yes, I am a beginner, but this is ridiculous...appreciate any help. Thanks!
First off, a table view has two "delegate" types -- the table view delegate and the table view data source. Your interface is being a delegate, but not a data source, for the table view.
If you add UITableViewDataSource to the interface, i.e.
#interface TableViewsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
and then compile, you'll probably get errors about missing methods for number of sections and for cell. After you add these to your implementation, the table view should work.
My guess is the table view tries to ask your class for number of sections in the table, and since your class doesn't actually respond to that selector, the code crashes.
Add
tblSimpleTable.delegate = self
in viewDidLoad
...and ensure you have connected it correctly in interface builder.
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.
I have a table view set up in IB. It's delegate/datasource are connected to this class:
#interface EditPlayersViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
I'm trying to call the reloadData method. If I use [self.view reloadData]; it doesn't respond, I guess because technically self.view isn't a UITableView. I tried to add the following:
IBOutlet UITableView *myTableView
and then I connected it to my table view in IB. Now my program crashes when the view loads. Any ideas?
Make EditPlayersViewController a subclass of UITableViewController rather than UIViewController. Dump the explicit interface implementations and the IBOutlet. Then, [self.tableView reloadData] should work.
Watch the console when it crashes and then bring up the debugger window. Both of these windows will give you great insight into what is happening. The data you're trying to load may be to culprit and not the reloadData call.
Make sure you have implemented the UITableView data source methods.
put break points in data source methods and try to find out where it is crashing.
UITableViewDataSource_Protocol/Reference
General Description:
To start with what works, I have a UITableView which has been placed onto an Xcode-generated view using Interface Builder. The view's File Owner is set to an Xcode-generated subclass of UIViewController. To this subclass I have added working implementations of numberOfSectionsInTableView: tableView:numberOfRowsInSection: and tableView:cellForRowAtIndexPath: and the Table View's dataSource and delegate are connected to this class via the File Owner in Interface Builder.
The above configuration works with no problems. The issue occurs when I want to move this Table View's dataSource and delegate-implementations out to a separate class, most likely because there are other controls on the View besides the Table View and I'd like to move the Table View-related code out to its own class. To accomplish this, I try the following:
Create a new subclass of UITableViewController in Xcode
Move the known-good implementations of numberOfSectionsInTableView:, tableView:numberOfRowsInSection: and tableView:cellForRowAtIndexPath: to the new subclass
Drag a UITableViewController to the top level of the existing XIB in InterfaceBuilder, delete the UIView/UITableView that are automatically created for this UITableViewController, then set the UITableViewController's class to match the new subclass
Remove the previously-working UITableView's existing dataSource and delegate connections and connect them to the new UITableViewController
When complete, I do not have a working UITableView. I end up with one of three outcomes which can seemingly happen at random:
When the UITableView loads, I get a runtime error indicating I am sending tableView:cellForRowAtIndexPath: to an object which does not recognize it
When the UITableView loads, the project breaks into the debugger without error
There is no error, but the UITableView does not appear
With some debugging and having created a basic project just to reproduce this issue, I am usually seeing the 3rd option above (no error but no visible table view). I added some NSLog calls and found that although numberOfSectionsInTableView: and numberOfRowsInSection: are both getting called, cellForRowAtIndexPath: is not. I am convinced I'm missing something really simple and was hoping the answer may be obvious to someone with more experience than I have. If this doesn't turn out to be an easy answer I would be happy to update with some code or a sample project. Thanks for your time!
Complete steps to reproduce:
Create a new iPhone OS, View-Based Application in Xcode and call it TableTest
Open TableTestViewController.xib in Interface Builder and drag a UITableView onto the provided view surface.
Connect the UITableView's dataSource and delegate-outlets to File's Owner, which should already represent the TableTestViewController-class. Save your changes
Back in Xcode, add the following code to TableTestViewController.m:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(#"Returning num sections");
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Returning num rows");
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Trying to return cell");
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
cell.text = #"Hello";
NSLog(#"Returning cell");
return cell;
}
Build and Go, and you should see the word Hello appear in the UITableView
Now to attempt to move this UITableView's logic out to a separate class, first create a new file in Xcode, choosing UITableViewController subclass and calling the class TableTestTableViewController
Remove the above code snippet from TableTestViewController.m and place it into TableTestTableViewController.m, replacing the default implementation of these three methods with ours.
Back in Interface Builder within the same TableTestViewController.xib-file, drag a UITableViewController into the main IB window and delete the new UITableView object that automatically came with it
Set the class for this new UITableViewController to TableTestTableViewController
Remove the dataSource and delegate bindings from the existing, previously-working UITableView and reconnect the same two bindings to the new TableTestTableViewController we created.
Save changes, Build and Go, and if you're getting the results I'm getting, note the UITableView no longer functions properly
Solution:
With some more troubleshooting and some assistance from the iPhone Developer Forums, I've documented a solution! The main UIViewController subclass of the project needs an outlet pointing to the UITableViewController instance. To accomplish this, simply add the following to the primary view's header (TableTestViewController.h):
#import "TableTestTableViewController.h"
and
IBOutlet TableTestTableViewController *myTableViewController;
Then, in Interface Builder, connect the new outlet from File's Owner to TableTestTableViewController in the main IB window. No changes are necessary in the UI part of the XIB. Simply having this outlet in place, even though no user code directly uses it, resolves the problem completely. Thanks to those who've helped and credit goes to BaldEagle on the iPhone Developer Forums for finding the solution.
I followed your steps, recreated the project and ran into the same problem. Basically you are almost there. There are 2 things missing (once fixed it works):
You need to connect the tableView of the TableTestTableViewController to the UITableView you have on the screen. As I said before because it is not IBOutlet you can override the tableView property and make it and IBOutlet:
#interface TableTestTableViewController : UITableViewController {
UITableView *tableView;
}
#property (nonatomic, retain) IBOutlet UITableView *tableView;
Next thing is to add a reference to the TableTestTableViewController and retain it in the TableTestViewController. Otherwise your TableTestTableViewController may be released (after loading the nib with nothing hanging on to it.) and that is why you are seeing the erratic results, crashes or nothing showing. To do that add:
#interface TableTestViewController : UIViewController {
TableTestTableViewController *tableViewController;
}
#property (nonatomic, retain) IBOutlet TableTestTableViewController *tableViewController;
and connect that in the Interface Builder to the TableTestTableViewController instance.
With the above this worked fine on my machine.
Also I think it would be good to state the motivation behind all this (instead of just using the UITableViewController with its own UITableView). In my case it was to use other views that just the UITableView on the same screenful of content. So I can add other UILabels or UIImages under UIView and show the UITableView under them or above them.
I just spent many hours pulling my hair out trying to figure out why a UITableView wouldn't show up when when I had it embedded in a separate nib instead of in the main nib. I finally found your discussion above and realized that it was because my UITableViewController wasn't being retained! Apparently the delegate and datasource properties of UITableView are not marked "retain" and so my nib was loading but the controller was getting tossed... And due to the wonders of objective-c I got no error messages at all from this... I still don't understand why it didn't crash. I know that I've seen "message sent to released xxx" before... why wasn't it giving me one of those?!?
I think most developers would assume that structure that they build in an interface builder would be held in some larger context (the Nib) and not subject to release. I guess I know why they do this.. so that the iPhone can drop and reload parts of the nib on low memory. But man, that was hard to figure out.
Can someone tell me where I should have read about that behavior in the docs?
Also - about hooking up the view. First, if you drag one in from the UI builder you'll see that they hook up the view property (which is an IBOutlet) to the table view. It's not necessary to expose the tableView, that seems to get set internally. In fact it doesn't even seem to be necessary to set the view unless you want viewDidLoad notification. I've just broken the view connection between my uitableview and uitableviewcontroller (only delegate and datasource set) and it's apparently working fine.
Yes for some reason (please chime in if anybody knows why...) tableView property of the UITableViewController is not exposed as an IBOutlet even though it is a public property. So when you use Interface Builder, you can't see that property to connect to your other UITableView. So in your subclass, you can create a tableView property marked as an IBOutlet and connect that.
This all seems hacky and a workaround to me, but it seems to be the only way to separate a UITableViewController's UITableView and put it somewhere else in UI hierarchy. I ran into the same issue when I tried to design view where there are things other than the UITableView and that was the way I solved it... Is this the right approach???
I was able to make this work. I built a really nice dashboard with 4 TableViews and a webview with video. The key is having the separate tableView controllers and the IBOutlets to the other tableview controllers defined in the view controller. In UIB you just need to connect the other tableview controllers to the file owner of the view controller. Then connect the tables to the corresponding view controllers for the datasource and delegate.