Newbie question here ...
I've created a Master-Detail Application project in Xcode 4.2 using ARC and Storyboard. I've modified the template to be:
MasterViewController.h
#import <UIKit/UIKit.h>
#class DetailViewController;
#interface MasterViewController : UITableViewController
{
NSMutableArray *items;
}
#property (strong, nonatomic) DetailViewController *detailViewController;
#property (strong, nonatomic) NSMutableArray *items;
#end
MasterViewController.m (snipits)
....
#synthesize items;
....
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.detailViewController = (DetailViewController)[[self.splitViewController.viewControllers lastObject] topViewController];
items = [[NSMutableArray alloc] initWithObjects:#"item 1", #"item 2", nil];
[self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:NO scrollPosition:UITableViewScrollPositionMiddle];
}
....
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [items count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return #"Test Section";
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell.
cell.textLabel.text = [items objectAtIndex:indexPath.row];
return cell;
}
This code will fail on this line when the program runs:
[self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:NO scrollPosition:UITableViewScrollPositionMiddle];
with this exception:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
If I cut the list(items) down to a single item, the MasterViewController will load without errors. I'm obviously doing something wrong, but I can't for the life of me figure out what it is. Anyone care to point out the obvious for me?
The template includes a UITableView that is set up for static cells. And it's actually one static cell. (this is why making your array one item long happens to kind of work)
But it seems you don't want static content here. So you just have to go into the storyboard, select the UITableView, go to the Attributes Inspector, and change the Content type to Dynamic Prototypes.
That should get you past this issue.
EDIT
A somewhat related issue is that you probably also want to use the prototype cell in the storyboard. To do that, just set the cell identifier of that prototype to the cell identifier you are using in your tableView:cellForRowAtIndexPath:.
And then omit the whole 'if (cell==nil)' part. The cell won't be nil.
So that method will look like this now:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell"; // <-- Make sure this matches what you have in the storyboard
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell.
cell.textLabel.text = [self.items objectAtIndex:indexPath.row];
return cell;
}
Hope that helps.
Related
I want to display a list of data on "UITableView".
When I run the code I get the following error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason:
'unable to dequeue a cell with identifier Cell - must register a nib or a class for the
identifier or connect a prototype cell in a storyboard'
I get the error given above when I run the code below. The error is thrown at the
cellForRowAtIndexPath function. How can I solve this error?
#interface TheViewController ()
#property (strong, nonatomic) NSMutableArray *myTData;
#property (weak, nonatomic) IBOutlet UITableView *tableViewOutlet;
#end
#implementation TheViewController
- (void)viewDidLoad
{
self.tableViewOutlet.delegate = self;
self.tableViewOutlet.dataSource = self;
self.tableViewOutlet.scrollEnabled = YES;
self.myData = [[NSMutableArray alloc] initWithObjects:#"obj1", #"obj2", nil];
[self.tableViewOutlet reloadData];
[super viewDidLoad];
}
#pragma mark UITableViewDataSource methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger) section {
return myData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"hede"];
}
[cell.textLabel setText: [myData objectAtIndex:indexPath.row]];
[cell.detailTextLabel setText:#"hede hodo"];
//
// Configure the cell..
return cell;
}
#pragma mark UITableViewDelegate methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
#warning Potentially incomplete method implementation.
// Return the number of sections.
return 1;
}
#end
The exception is exactly what it says it is.
In iOS 5, you would call [tableView dequeueReusableCellWithIdentifier:CellIdentifier] and if it didn't return one, you would create one. The new call -dequeueReusableCellWithIdentifier:forIndexPath: should have a NIB or cell class registered and it will then always succeed.
You should call either
- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier
or
- (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier
in your -viewDidLoad method.
In your storyboard, select the prototype cell, go to inspector and give the cell the identifier "Cell" or whatever you want as long as you have the same here : static NSString *CellIdentifier = #"Cell";
I am very new to XCode and I am trying to populate data into a table view that is a subview of a view controller. But I keep getting a runtime error and I cannot figure out why. Please help.
First thing I did was create the view in the storyboard, sized it, and left it as a Dynamic Prototypes table.
I then control-click dragged the table onto my View Controller class, and as expected it created a property:
#interface FAViewController () <UITableViewDataSource>
#property (strong, nonatomic) IBOutlet UITableView *myTable;
#end
Notice that I added the UITableViewDataSource Protocol. I then declared this class as the data source:
- (void)viewDidLoad
{
[super viewDidLoad];
self.myTable.dataSource= self;
}
Finally, I implemented the required required methods:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if ([tableView isEqual:self.myTable]) {
return 1;
}
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = #"Test";
return cell;
}
When I run the app, it takes me to this piece of code:
int main(int argc, char * argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([FAAppDelegate class]));
}
}
and says signal SIGBART. I hope I have provided all the relevant info. If not, please let me know.
Instead of :
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
Try:
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"cell"];
}
On the first example, when you say " UITableViewCell *cell = nil;", you are saying the object pointer isn't pointing to anything and then the error occurs when you try to use this object. On the example i gave, you are avoiding this to happen.
I searched too much, tried lot of thinks but i couldn't make it work.
I have a view controller, and in that controller i have a tableview which has custom cell.
I connect outlets,datasource and delegate but when i run the project, instead of my custom cells. UITableCell is shown and not showing data either. here is my .h and .m files
#import <UIKit/UIKit.h>
#class SelectMutantCell;
#interface MutantViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>{
UITableView *tableView;
IBOutlet SelectMutantCell *mutantCell;
}
#property (nonatomic, weak) IBOutlet UITableView *tableView;
#property (nonatomic, weak) SelectMutantCell *mutantCell;
- (IBAction)cancel:(id)sender;
#end
and here is my .m file
#implementation MutantViewController
#synthesize tableView = _tableView;
#synthesize mutantCell = _mutantCell;
NSArray *mutants;
- (void)viewDidLoad
{
[super viewDidLoad];
//mutants = [mutants initWithObjects:#"Keko",#"HEHE",#"PEPE", nil];
UINib *cellNib = [UINib nibWithNibName:#"SelectMutantCell" bundle:nil];
[self.tableView registerNib:cellNib forCellReuseIdentifier:#"SelectMutantCell"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"SelectMutantCell";
SelectMutantCell *cell = (SelectMutantCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSLog(#"---");
cell.nameLabel.text = #"Hehe"];
cell.descriptionLabel.text = #"hhe";
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 3;
}
the NSLog(#"---") is for debugging and it appears when running. the problem is in
cell.nameLabel.text = #"Hehe"];
cell.descriptionLabel.text = #"hhe";
this block, if i write cell.textLabel.text = "test" it works but i need my custom cell to shown.
any help will be appreciated..
Insert if(cell==nil){} loop
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"SelectMutantCell";
SelectMutantCell *cell = (SelectMutantCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[SelectMutantCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSLog(#"---");
cell.nameLabel.text = #"Hehe"];
cell.descriptionLabel.text = #"hhe";
return cell;
}
Looking at your cellForRowAtIndexPath: method, you never initialize the cell. Try doing it like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"SelectMutantCell";
SelectMutantCell *cell = (SelectMutantCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"SelectMutantCell" owner:nil options:nil];
for(id currentObject in topLevelObjects) {
if([currentObject isKindOfClass:[SelectMutantCell class]]) {
cell = (SelectMutantCell *)currentObject;
break;
}
}
}
NSLog(#"---");
cell.nameLabel.text = #"Hehe"];
cell.descriptionLabel.text = #"hhe";
return cell;
}
I had the same issue. To solve it check the followings :
in your nib file, you have removed the root view created by default, and dragged a UITableViewCell from XCode object browser, then set the custom type of the UItableViewCell to your subclass SelectMutantCell
you have linked the outlets
you have added the cell identifier to SelectMutantCell, as you would do in storyboard
last but not least, you didn't add the same cell in your storyboard TableView, it will conflit between the one from storyboard and the one from [self.tableView registerNib:cellNib forCellReuseIdentifier:#"SelectMutantCell"];
I'm doing this iPhone project where I need to have a (dynamic) table view inside a normal view controller. I didn't choose a Table View Controller because I need to put other stuff in the page. Imagine a page with text fields, buttons and my small table view of about 4-5 cells.
When I run the app, I need to touch a button to segue to this view. The I click the button, the app crashes and tells me that:
2012-07-22 14:40:57.304 How Many?[3055:f803] * Assertion failure in
-[UITableView _createPreparedCellForGlobalRow:withIndexPath:], /SourceCache/UIKit_Sim/UIKit-1914.84/UITableView.m:6061
This is my .H file:
#import <UIKit/UIKit.h>
#interface ProjectViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#end
This is my .M file:
#import "ProjectViewController.h"
#interface ProjectViewController ()
#end
#implementation ProjectViewController
//MyViewController.m
#pragma mark - Table View Data Source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSLog(#"numberOfSectionsInTableView");
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"numberOfRowsInSection");
return 5;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"cellForRowAtIndexPath");
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
NSLog(#"cellForRowAtIndexPath");
cell.textLabel.text = #"Test";
return cell;
}
#end
I control-dragged from the table view to my controller to set the delegate and the datasource.
What did I do wrong??
Thanks for your help.
Try to make an outlet in your .h file and wire it to the tableView in your storyboard
ProjectViewController.h
#property (nonatomic, strong) IBOutlet UITableView *myTableView;
ProjectViewController.m
#synthesize myTableView;
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"cellForRowAtIndexPath");
UITableViewCell *cell = [self.myTableView dequeueReusableCellWithIdentifier:#"cell"];
NSLog(#"cellForRowAtIndexPath");
cell.textLabel.text = #"Test";
return cell;
}
In your -cellForRowAtIndexPath, if you do this, you will be fine.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"cellForRowAtIndexPath");
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"cell"];
}
NSLog(#"cellForRowAtIndexPath");
cell.textLabel.text = #"Test";
return cell;
}
The problem is your cell never got memory allocated and initialized. That's why you get the error.
I need to create my own UITableViewCell using the xib file, to draw the graphic interface...
what are the right steps to create my new class and to use into my UITableView?
thanks in advance
In iOS5 you'll want to use the new:
registerNib:forCellReuseIdentifier:
Which basically does the same thing...
Personally I think that both suggested tutorials have a big flaw when it comes to reuseIdentifier. If you forget to assign it in interface builder or misspell it, you will load the nib each and every time cellForRowAtIndexPath gets called.
Jeff LaMarche writes about this and how to fix it in this blog post. Apart from reuseIdentifier he uses the same approach as in the apple documentation on Loading Custom Table-View Cells From Nib Files.
After having read all these articles I came up with following code:
Edit: If you are targeting iOS 5.0 and higher you'll want to stick with Duane Fields' answer
#interface CustomCellWithXib : UITableViewCell
+ (NSString *)reuseIdentifier;
- (id)initWithOwner:(id)owner;
#end
#implementation CustomCellWithXib
+ (UINib*)nib
{
// singleton implementation to get a UINib object
static dispatch_once_t pred = 0;
__strong static UINib* _sharedNibObject = nil;
dispatch_once(&pred, ^{
_sharedNibObject = [UINib nibWithNibName:NSStringFromClass([self class]) bundle:nil];
});
return _sharedNibObject;
}
- (NSString *)reuseIdentifier
{
return [[self class] reuseIdentifier];
}
+ (NSString *)reuseIdentifier
{
// return any identifier you like, in this case the class name
return NSStringFromClass([self class]);
}
- (id)initWithOwner:(id)owner
{
return [[[[self class] nib] instantiateWithOwner:owner options:nil] objectAtIndex:0];
}
#end
UINib (available in iOS 4.0 and later) is used here as a singleton, because although the reuseIdentifier is used, the cell still gets re-initialized about 10 times or so. Now cellForRowAtIndexPath looks like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCellWithXib *cell = [tableView dequeueReusableCellWithIdentifier:[CustomCellWithXib reuseIdentifier]];
if (cell == nil) {
cell = [[CustomCellWithXib alloc] initWithOwner:self];
}
// do additional cell configuration
return cell;
}
A video tutorial showing how to do this with Xcode 4.2 has been made. The author has written a blog post as well.
This tutorial takes you through the whole modern iOS 5 solution, from the process of creating the cell's xib and class files all the way to the finish:
http://mrmaksimize.com/ios/Custom-UITableViewCell-With-NIB/
`You can create custom cells in table view with the help of .xib file. First setup the table view in your view controller, create a new xib file with its class and use it in table view.
- (IBAction)moveToSubCategory:(id)sender;
#property (strong, nonatomic) IBOutlet UILabel *foodCategoryLabel;
#property (strong, nonatomic) IBOutlet UIImageView *cellBg;
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [foodCatArray count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"ExampleCell";
ExampleCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ExampleCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
[cell setTag:indexPath.row];
cell.cellBg.image=[UIImage imageNamed:[photoArray objectAtIndex:indexPath.row]];
cell.foodCategoryLabel.text=[foodCatArray objectAtIndex:indexPath.row];
return cell;
}
You can create CustomCell class with XIB that is inherited from UITableViewCell. We will just add category in tableview class .m file in following way. I think this is the easiest method which an be applied for custom cell creation.
#interface UITableViewCell(NIB)
#property(nonatomic,readwrite,copy) NSString *reuseIdentifier;
#end
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 30;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier=#"cell";
CustomCell *cell=[tableView dequeueReusableCellWithIdentifier:identifier];
if(cell==nil)
{
NSLog(#"New Cell");
NSArray *nib=[[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell=[nib objectAtIndex:0];
cell.reuseIdentifier=identifier;
}else{
NSLog(#"Reuse Cell");
}
cell.lbltitle.text=[NSString stringWithFormat:#"Level %d",indexPath.row];
id num=[_arrslidervalues objectAtIndex:indexPath.row];
cell.slider.value=[num floatValue];
return cell;
}
#end