I have a dynamically generated button on a detailviewcontroller (uisplitviewcontroller) that uses a uinavigation that when you tap will popover a uitableviewcontroller. The uitableviewcontroller pops up without any problems if I'm testint it with 0 sections. But when I change my section to 1 like so:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
#warning Potentially incomplete method implementation.
// Return the number of sections.
return 1;
}
It would give this error:
NSInternalInconsistencyException', reason: 'unable to dequeue a cell
with identifier MatchCell - must register a nib or a class for the
identifier or connect a prototype cell in a storyboard'
on this part:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
Also, I noticed that, when stepping in the code , it would go through the numberOfSectionsInTableView and numberOfRowsInSection more than once (usually twice or sometimes three times).
Any thoughts on what I'm doing wrong?
Related
Here is the story. I have a simple app in which I use 2 tabs, both of them with UITableView. The first tab/view is called "Favorites" and the second one is called "My Profile." In addition I have a custom UITable cell named "CustomViewCell.xib" with an identifier of the same name. FavoritesViewController is a subclass of UITableViewController and that one is running perfectly. But for the ProfileViewController I am using normal ViewController because I don't want the whole view to be UitableView. To make that possible, I the following to ProfileViewController.h:
#interface ProfileViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, strong) IBOutlet UITableView *tableView;
then in the viewDidLoad of ProfleViewController.m file I have:
[self.tableView registerNib:[UINib nibWithNibName:#"CustomViewCell" bundle:nil]
forCellReuseIdentifier:#"CustomViewCell"];
The following methods are implemented just as in the other tab that's working:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.myArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Here I am customizing the cell and returning it.
}
When i run the app, the cells are the right height, but are empty.
To debug I put a break point right before cellForRowAtIndexPath, and the app runs without an error which it shouldn't. So, the program is not even getting to this method. So, I think that's the reason the cells are empty. Do you guys have any idea what might be causing it to skip this particular method? can you also explain it in simpler terms because I'm newbie, you know?
In you ViewDidLoad method, add this code:
[self.tableView setDelegate:self];
[self.tableView setDataSource:self];
Then check again if the breakpoint works
Have you implemented a UITableViewDataSource? A UITableViewController is the delegate and datasource for the Table View it manages so you can define all those methods in the View Controller itself.
For a UITableView that is a subview of a UIViewController, you need to define the Table View's delegate and datasource.
See here: http://www.aboveground.com/tutorials/adding-a-uitableview-to-a-custom-uiview
I'm trying to reload the values of a table view after exiting from a seque. The process being: I perform the seque manually from the profile selection view, add a new profile name, return to the profile selection view. Then I would like to reload the table view adding the new profile name. It is running the code fine (same code as original entry into the scene), but I can't seem to get the native methods of numberOfRowsInSection and numberOfRowsInSection to repopulate the table view. I actually have to leave the screen and reenter it before the new profile name will update. Any thoughts?
//** performing seque manually
-(IBAction)buttonAddNewProfile:(id)sender
{
// creating object for profile selection screen
UIStoryboard *ProfileSelectionStoryboard=[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
// creating object for add new profile storyboard
AddNewProfileViewController *addnewprofileVC=[ProfileSelectionStoryboard instantiateViewControllerWithIdentifier:#"Add New Profile"];
// setting the transition style
addnewprofileVC.modalTransitionStyle=UIModalTransitionStylePartialCurl;
// performing the segue
[self presentViewController:addnewprofileVC animated:YES completion:nil];
// performing new table view load on return from new profile
[self loadUsers];
}
//** function to load the new profile names in.
-(void)loadUsers
{
// retreiving the users from the database
SQLiteFunctions *sql = [[SQLiteFunctions alloc] init];
// testing for successful open
if([sql openDatabase:#"users"])
{
// setting query statement
const char *query = "SELECT * FROM users;";
// testing for that profile name existing already
if([sql getUserRecords:query] > 0)
{
// initializing array
NSMutableArray *names = [[NSMutableArray alloc] init];
// loop through object compling an array of user names
for(Users *ProfileUser in sql.returnData)
{
// adding user name to the listview array
[names addObject:ProfileUser.user_name];
}
// setting table view array to local array
tableData = names;
}
}
}
//** methods to reload the table view
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
{
// returning the number of rows in the table
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
// setting up the table view cells for data population
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell"];
// testing for cell parameters
if (cell == nil)
{
// setting up cloned cell parameters
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MyCell"];
}
// setting cell values to the array row value
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
// returning the current row label value
return cell;
}
You have a few different options here:
1) The easiest is to simply reload the table every time that the view controller is about to display its view:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.tableView reloadData];
}
The downside though, is that this will be executed every time that the view is displayed, even when you don't necessarily need to reload the data.
2) If you are using storyboard's and targeting iOS 6+ then you can use an unwind segue to call a specific method on your view controller when going back from the add profile view controller. For more info, see this SO question/answers: Does anyone know what the new Exit icon is used for when editing storyboards using Xcode 4.5?
3) If you are targeting older versions of iOS or aren't using storyboards, then you can create a protocol with a method that should be called whenever a new profile is added and you can reload the data whenever that method is called. There are lots of questions here on SO which cover how to do this (like dismissModalViewController AND pass data back which shows how to pass data, but you can do the same thing to just call a method).
This the actual answer from lnafzinger in the comments above. Thanks again.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tableView reloadData];
}
It took me a bit to figure this out, but it is because you are using
the UIModalTransitionStylePartialCurl modalTransitionStyle. I guess
they don't call it because it doesn't completely leave the screen. If
you use a different style (like the default) then it will call
viewWillAppear. If you want to stay with that, then you should
probably use one of the other methods. – lnafziger
I am getting the following crash:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindCell with identifier Cell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
I do have the following in my ViewDidLoad:
[self.collectionView registerClass:[UICollectionViewCell class]
forCellWithReuseIdentifier:#"Cell"];
And the line that crashes is in the cellForItemAtIndexPath callback:
UICollectionViewCell *cell = [collectionView
dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
I've been searching for hours but cannot find any solution. I've tried subclassing the UICollectionViewCell but get the same error.
With breakpoints I have determined that the registerClass line is being executed before the dequeueReusableCellWithReuseIdentifier callback is executed.
I had this problem because I was calling registerClass before I was instantiating my table view object. Working code :
self.tableView = [[UITableView alloc] initWithFrame:self.view.frame];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
[self.view addSubview:self.tableView];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.tableView reloadData];
Also, don't forget the difference between a cell (register... forCellWithReuseIdentifier) and a supplementary view (register... forSupplementaryViewOfKind).
I was dequeing it correctly with the supplementary (header/footer) type, but I accidentally registered it as a cell type. Duh.
If you happen to experience this, in UICollectionViewController or UITableViewController, do as what rob mayoff said and make sure that your Collection View or Table View is hooked up property in your Storyboard.
Another common mistake is in the Storyboard you forgot to give the right CollectionID or CellID.
Once when I was working on collection view cells, I wrote:
static NSString *identifier = #"cell ";
Looking carefully, you will see an extra space at the end of the identifier string. After realizing my mistake, I hope this will be helpful to someone.
Reference:
could not dequeue a view of kind: UICollectionElementKindCell with identifier
I have a view controller
In storyboard, added tableview to view controller.
Created an IBOutlet for tableview to View controller's header file.
The view controller's header file includes an resultsarray
Changed the #interface to include delegates UITableViewDelegate, UITableViewDataSource
View controller implementation file has mandatory tableview protocols
(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
The view controller has search button in storyboard and IBAction in view controller header file. On click of search button, results are obtained. How do I load the array and redisplay tableview with results in search method. After I loaded the results in array, I tried [self viewdidload];, hoping the cells will be loaded. But didn't. I thought of calling
[self.detailView cellForRowAtIndexPath:?indexpath], but dontknow what the value of index path is. Appreciate help from guru's to load the UItableviewcell
Thanks
You should use reloadData or reloadSections methods of tableView in order to reload your tableView from data source.
// you fill your array with results here...
// and then call
[tableView reloadData];
This will call cellForRowAtIndexPath: methods for every cell to update its data.
Here is the reference.
I'm starting now with Xcode on 4.2 for iOS5 and there are a few changes and I'm now crossing a problem that I can't figure out a way to solve it.
I'm doing an example with a UITablwView that is populated programmatically with 2 Sections, 1st section with only 1 Row, and 2nd Section with 3 Rows.
My aim is to select a row from the table, and based on that row, the user will be redirected to different Views.
For example:
selecting section 0 row 0, app pushes to view 1 - name setting //
selecting section 1 row 0, app pushes to view 3 - address setting
The old fashion way, this is quite simple, just needed to init a UIViewController with initWithNibName and then push the view.
Now with the storyBoard everything changes, or at least I think it changes because I can't see how to get the same result since I can't set multiple segue's from the tableView to different UIViewControllers...and to do the old fashion way I can't see where I can get the NIB names from the views on the storyBoard to init an UIViewController to push.
Does any one knows how to get to this result??
Define two "generic" segues (identified as "segue1" and "segue2", for example) in the storyboard from your source view controller, one to each destination view controller. These segues won't be associated with any action.
Then, conditionally perform the segues in your UITableViewDelegate:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Conditionally perform segues, here is an example:
if (indexPath.row == 0)
{
[self performSegueWithIdentifier:#"segue1" sender:self];
}
else
{
[self performSegueWithIdentifier:#"segue2" sender:self];
}
}
I have the same problem as you do. The problem is that you can't link your tableViewCell to multiple view controllers. However you can link your source view itself to multiple view controllers.
Control-drag the master view controller (instead of table view cell) from the scene viewer to whatever view controller you want to link. You can do this as much as you want. Notice that the segue shown in source view controller scene should be something like "Push Segue from Root View Controller ..." instead of "Push Segue from NavCell to ...".
Identify each segue link a unique name like "toDetailView1"
Finally, custom the selection in your source view controllers:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row % 2 == 1) {
[self performSegueWithIdentifier:#"toDetailView1" sender:self];
} else {
[self performSegueWithIdentifier:#"toDetailView2" sender:self];
}
}
Like #陳仁乾 and #Marco explained was completely correct. To make everything a little bit easier I would recommend you to use a single NSArray which will be initialized when viewDidLoad. Just name the segues the same as your UIViewControllers, this way you can Display a correct description of what UIViewControllers you can choose from and you can also perform the segues from this NSArray:
(Actually I'm not sure if it can cause any problems calling the segue the same as the UIViewController you want to call. Please let me know if this is BadPractise)
viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
_arraySessions = [[NSArray alloc] initWithObjects:
#"MyViewControllerName", nil];
}
cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:#"overviewCell"
forIndexPath:indexPath];
[cell.textLabel setText:_arraySessions[indexPath.row]];
return cell;
}
didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[self performSegueWithIdentifier:_arraySessions[indexPath.row]
sender:self];
}