indexPath.row is always 0 - objective-c

I'm working on populating the table view with an array of dictionaries. The contents of the arrays and the dictionaries are parsed without problems. However, the table is populated with [array count] number of cells with contents with index 0 of the array. It seems to me that indexPath.row returns 0 for all cells. How do I populate each cell with the corresponding index?
- (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...
NSDictionary *term = [self.terms objectAtIndex:indexPath.row];
cell.textLabel.text = [term objectForKey:#"content"];
cell.detailTextLabel.text = [term objectForKey:#"created"];
return cell;
}
Thanks a lot!
Edit: Here's what I got for logging indexPath
2011-11-21 03:07:58.025 Demo[21269:f803] 2
indexes [0, 0]
2011-11-21 03:07:58.027 Demo[21269:f803] 2
indexes [1, 0]
Seems like the first index is updating while the second is not.
When I logged indexPath.row, however
2011-11-21 03:19:40.306 Demo[21546:f803] 0
2011-11-21 03:19:40.308 Demo[21546:f803] 0
So what should I use to get the value that is incrementing?
Thanks for the help again.

That block of code looks fine in itself. Maybe your tableview has multiple sections with one row each? What are you returning for the datasource methods tableView:numberOfRowsInSection: (should be [self.terms count]
) and numberOfSectionsInTableView: (should be 1).
If those are OK, put NSLog(#"%#",indexPath); somewhere in the method and post the output into your question.

I have just had a similar issue (indexPath.row was always 0) and noticed how much of an idiot I was. In my numberOfSectionsInTableView I was returning the [dataSet count] and in my tableView:numberOfRowsInSection I was returning 1. Should be the other way around. Oops!

Related

UITableView with dynamic sections and custom cells

My data structor looks like this:
Inside an NSArray I have a few objects from different classes. How the array looks like if something like this:
Let's say myArray has 3 objectAs. Each objectA and an NSArry that has objectBs
Now at runtime I do not know the array counts.
My UITableView displays one objectA per section. Each section has 1 row. Unless my objectA has an NSArray of objectBs with a count of greater than 0.
So the UITableView would look like this if all my objectA's has no arrays of objectB's in them.
Section 1: Row 1: `objectA instance
Section 2: Row 1: `objectA instance
Section 3: Row 1: `objectA instance
Lets say the 3rd objectA has an array of objectB's with a count of 1. My UITableView would look like this:
Section 1: Row 1: `objectA instance
Section 2: Row 1: `objectA instance
Section 3: Row 1: `objectA instance
Section 3: Row 2: `objectB instance
Now I am using two different UITableViewCells for each object so objectA would use CustomCell1 and objectB would use CustomCell2
Here is where I am getting stuck - I need to return the correct cell to the correct section / row.
So I made sure my UITableView knows what to expect.
I wrote the methods like so:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
ObjectA *objectA = self.myArray[section];
return [objectA.objectBArray count] +1;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.myArra count];
}
So numberOfRowsInSection takes a look at the objectBs array and returns its count + 1 so that even if its 0 there is always one row. (I need at least one row for objectA in the current section.
numberOfSectionsInTableView is straight forward - one section for each objectA in self.myArray
This seems to do exactly as I need.
I then got stuck on cellForRowAtIndexPath method.
This is how far I got:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell1 *cell1 = [tableView dequeueReusableCellWithIdentifier:#"cell1"];
CustomCell2 *cell2 = [tableView dequeueReusableCellWithIdentifier:#"cell2"];
ObjectA *objectA = self.myArray[indexPath.section]; //Each section has one ObjectA.
//Make sure we have some objectB's to display first
if ([objectA. objectBArray count] > 0){
ObjectB *objectb = (ObjectB*) objectA.objectB[indexPath.row];
//if the current section (section 3) has a indexPath 0 already
// index path 1 would have the first objectB
}
cell1.objectA = objectA;
cell2.objectB = objectB;
//Now return the correct cell for the current section / index path
}
So I need to check if the current section already has valid cell1 object if it does I then need to return cell2 to the second or third row. for objectB As row one must always have a cell1.
I know I am almost there. I just can't figure out how to return the correct cell.
Update
So the cellForRowAtIndexPath method is only being called three times. Here is what I did in numberOfRowsInSection method to make sure it returns the right number of rows:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
ObjectA *objectA = self.myArray[section];
NSLog (#"Section:%ld", (long)section);
NSLog(#"Returning %ld", (long)[objectA.objectBArray count]+1);
return [objectA.objectBArray count] +1;
}
My console shows this:
2014-07-16 19:36:17.488 App[15473:60b] Section:2
2014-07-16 19:36:17.488 App[15473:60b] Returning 2
2014-07-16 19:36:18.128 App[15473:60b] Section:0
2014-07-16 19:36:18.128 App[15473:60b] Returning 1
2014-07-16 19:36:19.063 App[15473:60b] Section:1
2014-07-16 19:36:19.063 App[15473:60b] Returning 1
Any ideas?
If there will always only be one objectA in each section then you can test if your indexPath.row is anything larger then zero (not the first row).
See if this does the trick:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell1 *cell1 = [tableView dequeueReusableCellWithIdentifier:#"cell1"];
CustomCell2 *cell2 = [tableView dequeueReusableCellWithIdentifier:#"cell2"];
ObjectA *objectA = self.myArray[indexPath.section]; //Each section has one ObjectA.
cell1.objectA = objectA;
//Check if not first row and objectB's exist
if (indexPath.row > 0 && [objectA. objectBArray count] > 0){
ObjectB *objectb = (ObjectB*) objectA.objectB[indexPath.row];
cell2.objectB = objectB;
return cell2;
}
return cell1;
}
This is an answer to the second issue I was having. After setting breakpoints in my view controller - I noticed my tableView was already loading cells before my call to [self.tableView reloadData];
Not sure why that was happening so a quick nil-check in my rows for items method solved the issue:
if the main array had no objects - return 0. If it did - return objectBArray count + 1; Now the cellForRowAtIndexPath is called the correct number of times.

How to display selected consumables in a table in Objective C

I am having an issue selecting appropriate consumables that I have set up in iTunes Connect to appear in my table in a nib file. (Using Ray Wenderlich's tutorial)
I have set up 11 consumables which are in two distinct sets; coins and categories.
What I want to do is have two buttons, each taking the user to a different table. Depending on the table a different set is displayed.
I have tried for hours to get this to work and I cannot do it; so I bow to the powers of the StackOverflow community to help.
Currently my set is as follows:
NSSet * productIdentifiers = [NSSet setWithObjects:
#"com.ac.scramble.coins1",
#"com.ac.scramble.coins2",
#"com.ac.scramble.coins3",
#"com.ac.scramble.coins4",
#"com.ac.scramble.coins5",
#"com.ac.scramble.category1",
#"com.ac.scramble.category3",
#"com.ac.scramble.category5",
#"com.ac.scramble.category8",
#"com.ac.scramble.category15",
#"com.ac.scramble.category30",
nil];
sharedInstance = [[self alloc] initWithProductIdentifiers:productIdentifiers
which is set up through iTunes Connect with no problem.
The evident problem here is that in my first nib which wants to show 6 rows, it is showing the final six in the list above (not sure why the final six rather than the first six...). This is fine, but in the second nib, which wants to show 5 rows, it is showing the final five from the list above. I don't want that - I want it to display the top five (the coins).
I've tried splitting the NSSet up into two and passing through but I cannot get that to work. I don't know if I can in the code somewhere specify which rows of the set I want to display. The pertinent code (I believe) which is probably where I need to do some trickery is:
- (void)reload {
_products = nil;
[self.table2 reloadData];
[[RageIAPHelper sharedInstance] requestProductsWithCompletionHandler:^(BOOL success, NSArray *products) {
if (success) {
_products = products;
[self.table2 reloadData];
}
//[self.refreshControl endRefreshing];
}];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
SKProduct *product = (SKProduct *) _products[indexPath.row];
cell.nameLabel.text = product.localizedTitle;
NSLog(#"Localized title: %#", product.localizedTitle);
cell.thumbnailImageView.image = [UIImage imageNamed:[thumbnails3 objectAtIndex:indexPath.row]];
cell.descriptionLabel.text = [descriptions3 objectAtIndex:indexPath.row];
[_priceFormatter setLocale:product.priceLocale];
//cell.detailTextLabel.text = [_priceFormatter stringFromNumber:product.price];
cell.progressLabel.text = [_priceFormatter stringFromNumber:product.price];
cell.descriptionLabel.text = product.localizedDescription;
}
Thanks to all in advance.
I managed to work out the answer and it was indeed splitting the set up. This may not be the most efficient way of doing this but I took the Set of 11 elements and depending on which one I wanted I either used the removeLastObject or removeObjectAtIndex[0] methods to obtain what I wanted. Thanks to everyone's help!

NSInternalInconsistency Exception in UITableView

- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
static NSString* CellIdentifier = #"MessageCellIdentifier";
MessageTableViewCell* cell = (MessageTableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[MessageTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
Message* message = [self.dataModel.messages objectAtIndex:indexPath.row];
[cell setMessage:message];
return cell;
}
I am developing an chat application in which i am getting exception when sending and receiving messages happening at the same time.The following is the exception message
Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit/UIKit-2380.17/UITableView.m:1070 2013-04-30
16:55:14.314 [2689:907] Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'Invalid update: invalid
number of rows in section 0*.
The number of rows contained in an existing section after the update (19) must be equal to the number of rows contained in that section before the update (17), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
- (int)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.dataModel.messages count];
}
- (void)didSaveMsg:(NSMutableArray *)array1
{
self.dataModel.messages = array1;
[tableview insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:array1.count-1 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
[self scrollToNewestMessage];
}
- (void)scrollToNewestMessage
{
dispatch_after(DISPATCH_TIME_NOW, dispatch_get_main_queue(), ^(void){
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:(self.dataModel.messages.count - 1) inSection:0];
[tableview scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
});
[tableview reloadData];
[[DBModel database]updateMessageCount1:mobileNo cnt:#"0"];
}
The error message is fairly self explanatory - you are telling the table view you want to insert a single cell, but in the table's datasource are then saying it has two extra cells to display (19 instead of 17).
The problem almost certainly isn't in the code you've posted, it will be either in the numberOfRows method of your datasource, or in the code at the point at which you insert the extra cell.

NSInternalInconsistencyException with UITableViewController and a Storyboard-Pop

I integrated GrabKit in my iPhone-App, which is a Library to Grab Photos from social Networks. Now I have the following situation/problem:
I have a UITableViewController - AlbumListViewController.
Then there's a UITableViewCell - AlbumCellViewController.
When you tap on one of these cells - albums with photos
There's a UITableViewController - PhotoListViewController
and a UITableViewCell - PhotoCellViewController.
Everything here works just finde, I can browse albums, choose one, browse the photos in it and then when I choose one of the single photos, there is a PushViewController to my SetPhotoViewController, which displays the selected image in Fullscreen.
Now when I want to use the back-Button of my navigation bar in the SetPhotoViewController, the crashes with the following message:
*** Assertion failure in -[UISectionRowData refreshWithSection:tableView:tableViewRowData:], /SourceCache/UIKit_Sim/UIKit-2372/UITableViewRowData.m:400
2012-10-22 22:49:32.814 Amis[1820:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Failed to allocate data stores for 1073741821 rows in section 1. Consider using fewer rows'
*** First throw call stack:
(0x23de012 0x1b63e7e 0x23dde78 0x15f9f35 0xc8f83b 0xc923c4 0xb56fa2 0xb5692c 0x1690f 0x1cd653f 0x1ce8014 0x1cd87d5 0x2384af5 0x2383f44 0x2383e1b 0x2a9a7e3 0x2a9a668 0xaab65c 0x42fd 0x2b75)
libc++abi.dylib: terminate called throwing an exception
DataSource and Delegate of my two UITableViewControllers are both set to File's Owner.
When I debug trough the code, I can't find any special things, all photos can be loaded, all the arrays are filled with data, there's nothing strange.
Here are the two functions of the PhotoListViewController which get called, as soon as I press the back button on my NavigationController:
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
NSLog(#"%i", indexPath.row);
NSLog(#"%ii", indexPath.section);
// Extra Cell
if ( indexPath.section > _lastLoadedPageIndex ){
static NSString *extraCellIdentifier = #"ExtraCell";
cell = [tableView dequeueReusableCellWithIdentifier:extraCellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:extraCellIdentifier];
}
cell.textLabel.text = #"load more";
cell.textLabel.font = [UIFont fontWithName:#"System" size:8];
} else {
static NSString *photoCellIdentifier = #"photoCell";
cell = [tableView dequeueReusableCellWithIdentifier:photoCellIdentifier];
if (cell == nil) {
cell = [[[NSBundle mainBundle] loadNibNamed:#"PhotoRowViewController" owner:self options:nil] objectAtIndex:0];
}
}
// setting of the cell is done in method [tableView:willDisplayCell:forRowAtIndexPath:]
return cell;
}
and..
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
// extra cell
if ( [cell.reuseIdentifier isEqualToString:#"ExtraCell"] ){
if ( state == GRKDemoPhotosListStateAllPhotosGrabbed ) {
cell.textLabel.text = [NSString stringWithFormat:#" %d photos", [[_album photos] count] ];
}else {
cell.textLabel.text = [NSString stringWithFormat:#"Loading page %d", _lastLoadedPageIndex+1];
[self fillAlbumWithMorePhotos];
}
} else // Photo cell
{
NSArray * photosAtIndexPath = [self photosForCellAtIndexPath:indexPath];
[(PhotoRowViewController*)cell setPhotos:photosAtIndexPath];
}
}
What am I missing?
Edit: The code of the numberOfRowsInSection-Method:
If I debug it, the first time res is equal 0, the second time the method gets called, res is equal 322121535.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSUInteger res = 0;
if ( state == GRKDemoPhotosListStateAllPhotosGrabbed && section == _lastLoadedPageIndex ) {
NSUInteger photosCount = [_album count];
// Number of cells with kNumberOfPhotosPerCell photos
NSUInteger numberOfCompleteCell = (photosCount - section*kNumberOfRowsPerSection*kNumberOfPhotosPerCell) / kNumberOfPhotosPerCell;
// The last cell can contain less than kNumberOfPhotosPerCell photos
NSUInteger thereIsALastCellWithLessThenFourPhotos = (photosCount % kNumberOfPhotosPerCell)?1:0;
// always add an extra cell
res = numberOfCompleteCell + thereIsALastCellWithLessThenFourPhotos +1 ;
} else if ( section > _lastLoadedPageIndex) {
// extra cell
res = 1;
} else res = kNumberOfRowsPerSection;
return res;
}
I'm the developer of GrabKit. Thanks for using it :)
Actually, the controllers in GrabKit are there for demonstration purpose only, they are not designed to be used "as is" in a project, and more specifically : The GRKDemoPhotosList controller was not made to have another controller pushed in the controllers hierarchy.
So what you need is just a little fix to make grabKit demo's controllers fit to your project :)
I guess the problem is the following :
_ in [GRKDemoPhotosList viewWillAppear], the method fillAlbumWithMorePhotos is called.
_ when you pop back from your controller to GRKDemoPhotosList, this method is called one more time, and it generates this bug.
Try to add a flag in the viewWillAppear method, to avoid calling fillAlbumWithMorePhotos twice, I guess it'll work fine.
Feel free to contact me by mail ( pierre.olivier.simonard at gmail.com ) or on twitter ( #pierrotsmnrd ) if you need more informations or help :)

Unable to reach 0th section of UITableView from UITableViewController

I have a table view form which user is supposed to enter some information (question and choices) in. Basically, when user clicks the last section, text fields and other elements are being collected.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section==0) {
AskCellQuestion *cell;
cell = [tableView dequeueReusableCellWithIdentifier:#"askQuestionCell"];
if (cell == nil) {
cell = [[AskCellQuestion alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"askQuestionCell"];
}
...
cell.questionText.delegate = cell;
return cell;
} else if (indexPath.section==1) {
if (indexPath.row < numberOfChoices) {
AskCellChoice *cell;
cell = [tableView dequeueReusableCellWithIdentifier:#"askChoiceCell"];
if (cell == nil) {
cell = [[AskCellChoice alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"askChoiceCell"];
}
...
cell.choiceText.delegate = cell;
...
return cell;
} else {
AskCellChoiceAdd *cell;
cell = [tableView dequeueReusableCellWithIdentifier:#"askChoiceAddCell"];
if (cell == nil) {
cell = [[AskCellChoiceAdd alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"askChoiceAddCell"];
}
return cell;
}
} else if (indexPath.section==2) {
...
}
// Configure the cell...
return 0;
}
In didSelectRowAtIndexPathfunction, I'm trying to access these text fields and take their values:
UITableView * questionFormView = [self tableView];
AskCellQuestion * questionCell = (AskCellQuestion *)[questionFormView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
NSString * questionText = questionCell.questionText.text;
NSLog(#"TXt: %#",questionText);
UIImage * questionImage = questionCell.questionImage;
NSLog(#"IMG: %#",questionImage);
NSString * questionVideo = questionCell.youtubeVideoID;
NSLog(#"VID: %#",questionVideo);
for (int i = 0; i < numberOfChoices; i++) {
AskCellChoice * choiceCell = (AskCellChoice *)[questionFormView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:1]];
NSLog(#"C TXt: %#",choiceCell.choiceText.text);
NSLog(#"C IMG: %#",choiceCell.choiceImage);
NSLog(#"C VID: %#",choiceCell.youtubeVideoID);
}
It is giving this output in console:
2012-03-17 01:04:46.700 x[2346:207] TXt: (null)
2012-03-17 01:04:46.701 x[2346:207] IMG: (null)
2012-03-17 01:04:46.701 x[2346:207] VID: (null)
2012-03-17 01:04:46.701 x[2346:207] C TXt: TEST CHOICE 1
2012-03-17 01:04:46.701 x[2346:207] C IMG: <UIImage: 0x6ec75f0>
2012-03-17 01:04:46.702 x[2346:207] C VID: FMij4sZioBM
2012-03-17 01:04:46.702 x[2346:207] C TXt: TEST CHOICE 2
2012-03-17 01:04:46.702 x[2346:207] C IMG: <UIImage: 0x6e7ce30>
2012-03-17 01:04:46.702 x[2346:207] C VID: GfIcEzFzqKE
In short, I can not access the text field in section 0. I tried adding a second row and it returned null too. I tried swapping question and choice cells' sections, that time it returned null for section 0 which corresponded to choices. Question cell worked well. I also tried increasing section numbers, so question cells were in section 1, choices were section 2 etc... then it returned null for section 1. I couldn't figure out what is going on, it's a really weird problem.
By the way, I can access the cell in didSelectRowAtIndexPath when indexPath is equal to the index path of the row in section 0. But when it's not, it's returning null when I do [NSIndexPath indexPathForRow:0 inSection:0].
For example in didSelectRowAtIndexPath:
if (indexPath.section==4) {
NSLog(#"TEST 1 - %#", ((AskCellQuestion *)[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]).questionText.text);
//[self askTheQuestion];
} else if (indexPath.section==0) {
NSLog(#"TEST 2 - %#", ((AskCellQuestion *)[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]).questionText.text);
NSLog(#"TEST 3 - %#", ((AskCellQuestion *)[tableView cellForRowAtIndexPath:indexPath]).questionText.text);
}
Gives this output when I write 'fooBar' to the question input in section 0 and click the cell at section 4 ('Ask' button):
2012-03-17 01:38:47.125 x2516:207] TEST 1 - (null)
and gives this when I click the cell at section 0, which is the cell with question input:
2012-03-17 01:38:44.782 x[2516:207] TEST 2 - fooBar
2012-03-17 01:38:44.793 x[2516:207] TEST 3 - fooBar
Thanks in advance...
I am thinking that to press the Add cell (indexPath section == 1, row == numberOfChoices), the cell at section 0, row 0 is outside the screen. As I understand UITableViews, UITableViewCells are being reused. Generally, if the cell is outside of the screen, it goes into the reusable pool. (If I'm wrong, please correct me.) Calling a cell outside the screen may or may not give the correct values. I would suggest storing the values in the cells somewhere else (like an #property) so that you can retrieve them later.