General description:
To get started with what works, I have a UITableView that has been placed in an Xcode-generated view using Interface Builder. The owner of the view file is configured to a subclass created by Xcode, UIViewController . In this subclass, I added the working implementations of numberOfSectionsInTableView: tableView:numberOfRowsInSection: and tableView:cellForRowAtIndexPath: and the Table View dataSource and delegate connected to this class through the File Owner in Interface Builder.
The above configuration works without problems. The problem arises when I want to move this kind of dataSource table and delegate changes to a separate class, most likely because there are other controls in the view besides the table view, and I would like to move the table view related code with its own class. To do this, try the following:
- Create a new subclass of
UITableViewController in Xcode - Move the well-known good implementations of
numberOfSectionsInTableView: tableView:numberOfRowsInSection: and tableView:cellForRowAtIndexPath: to a new subclass - Drag the
UITableViewController to the top level of the existing XIB in the InterfaceBuilder, remove the UIView / UITableView that are automatically created for that UITableViewController , then set the UITableViewController class to the new subclass - Remove previously working
UITableView existing dataSource and delegate connections and connect them to the new UITableViewController
When done, I don't have a working UITableView . I get one of three results that may seem random:
- When a
UITableView loads, I get a runtime error indicating that I am sending tableView:cellForRowAtIndexPath: object that does not recognize it. - When a
UITableView loads, the project breaks into a debugger without errors - No error, but
UITableView not showing
With some debugging and creating a basic project to reproduce this problem, I usually see the third option above (no error, but no visible table view). I added some calls to NSLog and found that although numberOfSectionsInTableView: and numberOfRowsInSection: both called, cellForRowAtIndexPath: no. I am convinced that I missed something very simple and hoped that the answer might be obvious to someone who has more experience than me. If this is not an easy answer, I would be happy to update the code or sample project. Thank you for your time!
Complete steps to play:
- Create a new iPhone OS, View-based app in Xcode and name it
TableTest - Open
TableTestViewController.xib in Interface Builder and drag the UITableView onto the provided surface. - Connect the
UITableView dataSource and delegate -outlets to the file owner, which should already represent the TableTestViewController class. Save the changes. - Return to 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 in a UITableView
Now, to try to move this UITableView logic into a separate class, first create a new file in Xcode by selecting a subclass of UITableViewController and calling the TableTestTableViewController class
- Remove the above code snippet from
TableTestViewController.m and place it in TableTestTableViewController.m , replacing the standard implementation of these three methods with ours. - In the Builder interface, in the same
TableTestViewController.xib file TableTestViewController.xib drag the UITableViewController into the main IB window and delete the new UITableView object that automatically appeared with it - Set the class for this new
UITableViewController to TableTestTableViewController - Remove the
dataSource and delegate bindings from the previously existing UITableView and reconnect the same two bindings to the new TableTestTableViewController that we created. - Keep changes, build and go, and if you get the results I get, please note that the
UITableView no longer functioning properly
Solution: A few more troubleshooting problems and some help from the iPhone Developer Forums , I have documented a solution! The main subclass of the project's UIViewController requires an output that points to an instance of the UITableViewController . To do this, simply add the following to the header of the main view ( TableTestViewController.h ):
#import "TableTestTableViewController.h"
and
IBOutlet TableTestTableViewController *myTableViewController;
Then, in the Builder interface, connect the new outlet from File Owner to the TableTestTableViewController in the IB main window. No changes are required in the XIB user interface part. Just having this outlet in place, even if the user code does not use it directly, it completely fixes the problem. Thanks to those who helped and credited BaldEagle on the iPhone developer forums to find a solution.
objective-c iphone cocoa-touch uitableview
Adam Alexander Oct. 31 '08 at 17:48 2008-10-31 17:48
source share