I created a iOS tabbed application using xcode 4.2 and storyboard. I added one tableviewcontroller with custom cell on it, when clicking the row, I want to open one tableviewcontroller, i used the following code below
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
categoryClass *cc = [datas objectAtIndex:indexPath.row];
[tableView deselectRowAtIndexPath:indexPath animated:NO];
iSubProducts *subProducts = [[iSubProducts alloc] init];
subProducts.title = cc.categoryName;
subProducts.catID = cc.categoryID;
[[self navigationController] pushViewController:subProducts animated:YES];
[subProducts release];
}
but when I click the row it gives me the following error:
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath
on my iSubProducts tableviewcontroller, i have the following:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"myCell2";
iSubProductsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
productSubClass *cc = [datas2 objectAtIndex:indexPath.row];
NSLog(#"Product Name: %#", cc.productName);
cell.txtProductName.text = cc.productName;
cell.txtProductDesc.text = cc.productDesc;
return cell;
}
I assume this is where the error occurs, the cell is returning a nil value. When I try to attach the iSubProducts tableviewcontroller using or from a button, it all works fine, but if its coming from row clicked, this error shows up.
Im quite new with iOS development, and maybe there is a error opening tableviewcontroller from a tableviewcontroller with a custom cell on it. I've been bangin my head for 2 days now and googled a lot, unfortunately I didn't find any solution. I'm pretty sure there's no error on the iSubProducts tableviewcontroller since its working if i tried pushing it from a button. Please I need advice on this one, Im so stucked right now with this issue. Thank you everyone.
note sure how beneficial this is.. but just today I had trouble moving from one tableview to another view after clicking the row..
I stayed completely away from DidSelectRowAtIndexPath. Instead I used the segue (which was what I was aiming at).
this code snipped is from apple's storyboard example that uses tables.
http://developer.apple.com/library/ios/#samplecode/SimpleDrillDown/Listings/Classes_RootViewController_m.html#//apple_ref/doc/uid/DTS40007416-Classes_RootViewController_m-DontLinkElementID_10
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"ShowSelectedPlay"]) {
NSIndexPath *selectedRowIndex = [self.tableView indexPathForSelectedRow];
DetailViewController *detailViewController = [segue destinationViewController];
detailViewController.play = [dataController objectInListAtIndex:selectedRowIndex.row];
}
}
This all assumign you start using the segues in the storyboard feature and make sure to use the identifiers for the segues.
You just have to create a prototype cell first in the designer so that you can drag out a segue from the cell to the destination view.
Related
I have a table view displaying a list of contacts and when you click a cell, a detail view controller pops up with labels showing the contact name, number, fax, and address. My problem is that every time I click a cell, the first value in the plist pops up no matter which cell i click. I found my error in indexPath when NSLog(#"%#",indexPath); returned null everytime. I think the problem is in this method but it looks the same in other classes and works fine.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showCountyInfo"])
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSLog(#"%#",indexPath);
TSPBookCoverViewController *destViewController = segue.destinationViewController;
destViewController.countyName = [[self.books objectAtIndex:indexPath.row] objectForKey:#"Name"];//error
destViewController.phoneName = [[self.books objectAtIndex:indexPath.row] objectForKey:#"Phone"];
destViewController.faxName = [[self.books objectAtIndex:indexPath.row] objectForKey:#"Fax"];
destViewController.addressName = [[self.books objectAtIndex:indexPath.row] objectForKey:#"Address"];
}
}
When I enter integers instead of indexPath.row, it works like it should, so the problem is here I just can't find it. Sorry if it's obvious I've tried looking for awhile now!
Edit:
Here is didSelectRowAtIndexPath method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// Perform Segue
[self performSegueWithIdentifier:#"showCountyInfo" sender:self];
}
The issue is with the following code:
[tableView deselectRowAtIndexPath:indexPath animated:YES];
You are deselecting the cell inside the didSelectRowAtIndexPath: method. So the indexPathForSelectedRow will always return nil
Best way for you to resolve it is to get the Dictionary from self.books array in
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
and then perform the segue and get values from that dictionary in prepareForSegue
I am currently making a tableView for my app, and I've got my cells from a .plist file. However I want to be able to enter my second view controller no matter, what cell I click on, the difference should be that the UIText for my second viewController will depend on which cell I click.
So far, I have imagined something like;
if(tableview.tag == 1){
myUIText.text = #"a";
}else if(tableview.tag == 2){
myUIText.text = #"b";
etc.......
Will this work using the same view controller, same UIText? If not, then how?
And how can I set the tags for my array in my .plist file?
I would appreciate your answers
EDIT: Here is a sample of two methods;
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.items count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString * id = #"plistdata";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:id forIndexPath:indexPath];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:id];
}
cell.textLabel.text = self.items[indexPath.row];
return cell;
}
More information is certainly needed by I will make some assumptions on your code and see if it helps any. I assume the the text you want to send is the title of the cell the person clicked on. Now how you send that to the next VC will differ depending on if you are using a segue or not. If you are using a segue you can do something like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"mySegue"]) {
UITableViewCell *cell = (UITableViewCell *)sender;
UpcomingViewController *viewController = segue.destinationViewController;
viewController.textView.text = cell.chapterText;
}
}
However if you are using didSelectRowAtIndexPath then:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UpcomingViewController *viewController = [[UpcomingViewController alloc] init];
viewController.textView.text = self.arrayOfChapterText[indexPath.row];
[self.navigationController pushViewController:viewController animated:YES];
}
Now again because your question wasn't very clear on your scenarios I have taken some liberties with what I think you are probably trying to do. I assume that the view controller that will show after you choose an item will have the UITextView as a public property so that you can set it before pushing or segueing to your new view. I also assume in the didSelectRowAtIndexPath that you are using a UINavigationController.
Hope this helps.
I am just beginning to learn objective-c and programming in general, and I am really stuck on this issue. I am using storyboards to create an app that keeps scores for different types of games. I have a master view controller that is a table view and it has prototype cells with detail labels. There is an AddKeeperViewController that allows the user to input player names and the game type. The game type is then used as the detail label for the prototype cells.
I want to then have each cell push to a different view controller, depending on what the detail text label is. I only have 2 game types at the moment, I know I need to set up logic in tableView didSelectRowAtIndexPath that will choose which segue to take. I set up my segues from the view controller, not the cells, and they each have a unique identifier. I just don't know how to set up my if statements to use the gameType as the deciding factor for which segue to take.
Here is some of my code from my MasterViewController.m file:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"scoreKeeperCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
scoreKeeper *keeperAtIndex = [self.dataController objectInListAtIndex:indexPath.row];
[[cell textLabel]setText:keeperAtIndex.name];
[[cell detailTextLabel] setText:keeperAtIndex.gameType];
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if(cell.detailTextLabel) {
//statement
}
if ([[segue identifier] isEqualToString:#"ShowKeeperDetails"]) {
MADDetailViewController *detailViewController = [segue destinationViewController];
detailViewController.keeper = [self.dataController objectInListAtIndex:[self.tableView indexPathForSelectedRow].row];
}
}
It seems like you're on the right track. However, I think you're waiting a bit too long to choose which segue to take. Perhaps something like this would work for you:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ([cell.detailTextLabel.text isEqualToString:#"TEXT"])
{
[self performSegueWithIdentifier:#"segueTypeOne" sender:nil];
}
else
{
[self performSegueWithIdentifier:#"segueTypeTwo" sender:nil];
}
}
You may also create different cell's prototypes, each one connected with a different segue leading to different views, and then use the right prototype to obtain cells in dequeueReusableCellWithIdentifier.
I created a universal master-detail application. I have a table view within a custom class (MasterViewController class). This is a UITableViewController class.
Using Storyboard, I created a custom cell in my iPhone table view. The custom cell contains 3 labels and 1 image.
In StoryBoard, this table view datasource and delegate is set to the MasterViewController class.
My custom table view cell has 'User Interaction Enabled' in the View section of the attribute inspector.
In my MasterViewController class, the UITableViewDataSource methods such as 'numberOfSectionsInTableView' are working fine.
I have a seque defined between the table view and a detailed view.
When I run the application and select a cell in the table view, the didSelectRowAtIndexPath is not called for the iPhone. My prepareForSegue method executes and the segue occurs.
I have read quite a number of posts on didSelectRowAtIndexPath not being executed, but I have not been able to solve my problem.
Any hints would be very much appreciated.
My custom cell identifier is ConversationCell. The segue identifier is ShowConversationDetails.
I debug with a breakpoint on the first line of numberOfRowsInSection and this method is never entered.
The segue works and the detail view displays my label with 'Hello' text.
Some Code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
//NSLog(#"Rows %lu",(unsigned long)[sectionInfo numberOfObjects]);
return [sectionInfo numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ConversationCell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
[[self.fetchedResultsController sections] count]);
NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
self.detailViewController.detailItem = object;
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowConversationDetails"]) {
NSIndexPath *selectedIndex = [self.tableView indexPathForSelectedRow];
Event *e = nil;
e = [self.fetchedResultsController objectAtIndexPath:selectedIndex];
UIViewController *destinationViewController = [segue destinationViewController];
[segue.destinationViewController setLabel:#"Hello"];
}
}
MASTERVIEWCONTROLLER:
Here is my interface for above;
#interface MasterViewController : UITableViewController <NSFetchedResultsControllerDelegate,ASIHTTPRequestDelegate,UITableViewDelegate, UITableViewDataSource>
{
NSMutableArray *eventsArray;
}
This may be a clue to my problem. When I add the following code to prepareForSeque
NSIndexPath *selectedIndex = [self.tableView indexPathForSelectedRow];
NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:selectedIndex];
NSString *messageTableID = [[object valueForKey:#"messagetableid"] description];
selectedIndex is empty as if a row is no longer selected when prepareForSeque is executing.
By the way, just to be safe, I removed the app from the simulator and then did a Clean on the project and nothing changed.
Tim
In addition to the checks you have already mentioned, here are a few other ones you might want to consider:
Check that the method is exactly this (no difference in letter cases) :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Check that the controller implements the UITableViewDelegate protocol
Check that interaction does work (change the selection style option so that the cell changes color on touch events)
Check that you don't have any view inside that is first responder and takes away the interaction (remove any view in the cell to test)
Try to programmatically allow selection on the table [tableView setAllowsSelection:YES];
Are you sure that your UITableViewDelegate object is correctly being set as the table view's delegate? (This is separate from setting it as the data source.)
I ended up deleting my MasterViewController and DetailViewController. I recreated them and things are now working. Not sure what I did wrong the first time. Thanks for everyone that offered advice.
Tim
I'm using Core Data to manage Thing(s) and then UITableViewController/UITableViewCell to present a list of Things. However, a Thing object has more data than just what I display in the text property of the UITableViewCell, and when I segue from the UITableViewController to a more detailed view controller of Thing, what I really want is a pointer to the Thing object so I can pass it on to the next view controller.
For example:
-(UITableViewCell*)tableView:(UITAbleView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ENTRY_LOG;
// Ask the NSFetchedResultsController for the NSManagedUserObject at the row in question
Thing* thing = [self.fetchedResultsController objectAtIndexPath:indexPath];
// For brevity skip dequeueReusable...
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.textLabel.text = thing.name;
EXIT_LOG;
return cell;
Now, assume I assume the segue connected appropriately:
- (void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender {
ENTRY_LOG;
UITableViewCell* cellSender = (UITableViewCell*)sender;
// I want to do this:
Thing* thingHandle = [cellSender someMessageToGetThingReference];
[segue.destinationViewController setThing:thing];
// and I don't want to do this
// setup NSFetchRequest and predicate to get thing where 'name = cellSender.text'
[segue.destinationViewController setThing:thing];
EXIT_LOG;
}
If I could get the indexPath that the cell is at I could then use my NSFetchResultsController to at least get the objectAtIndexPath again, perhaps call - (NSIndexPath *)indexPathForSelectedRow in the prepareForSegue against the UITableView and proceed from there.
Perhaps I am missing something obvious, but to get the cell's index path, assuming you are segueing from a UITableViewController, can't you use:
NSIndexPath *indexPath = [[self tableView] indexPathForCell:cellSender];