I'm having a little trouble with a tableView.
In this case, I have 4 sections.
Sections 0,1,2 have 1 cell.
Section 3 has 2 cells.
I'm now receiving the error,
Terminating app due to uncaught exception 'NSRangeException', reason:
'-[__NSCFArray objectAtIndex:]: index (1) beyond bounds (1)'
Now I understand this is trying to reference a cell that isn't within the section?
Where I'm struggling is the count for each section is correct, like below.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSLog(#"Sections: %d", [_timetableDataArray count]);
return [_timetableDataArray count];
}
This returns, as expected,
Sections: 4
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSDictionary *sectionContents = [_timetableDataArray objectAtIndex: section];
NSLog(#"Section %d contains %d items", section, [sectionContents count]);
return [sectionContents count];
}
The log for the above returns,
Section 3 contains 2 items
Section 0 contains 1 items
Section 1 contains 1 items
Section 2 contains 1 items
This is absolutely correct.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Iterating --- section: %d row: %d", indexPath.section, indexPath.row);
}
The above method never even gets to NSLog. It crashes before this.
If I change my data array, so each section has 2 items, everything works fine.
Here is my data, http://pastebin.com/q5rbsvC8
I just don't understand where this crash is coming from when numberOfRowsInSection is returning the right number of rows per section.
I originally thought it might be a problem with 0-index's, but I changed these to start from 1 and it didn't help.
Any help/advice is greatly appreciated.
Thanks,
Adrian
Try to NSLog for section in - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section before
NSDictionary *sectionContents = [_timetableDataArray objectAtIndex: section];
to see if any unexpected values of section are coming in?
Related
I'm having the following issue raised by Crashlytics :
[__NSArrayM objectAtIndexedSubscript:]: index 5 beyond bounds for empty array
-TopicListViewController tableView:cellForRowAtIndexPath:]
While accessing the dataSource with indexPath.row.
We have some asynchronous data update updating the datasource, and that variable is nonatomic.
Would it be possible that cellForRowAtIndexPath is called while the dataSource is being updated? Hence causing to access an index that doesn't exist anymore?
Can it be because the variable is nonatomic?
Here's the relevant code :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.row > [self.tableData count] - 1 || ![self.tableData isValidArray]) {
return nil; //Some protection to prevent this issue...
}
TopicCell * cell = (TopicCell *)[tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
cell.delegate = self;
NSDictionary * data = nil;
if (self.we_isSearching) {
data = self.we_searchResult[indexPath.row];
} else {
data = [self.tableData objectAtIndex:indexPath.row]; //Crashes here
}
"index 5 beyond bounds for empty array" simply states that either you didn't initialise your array or the range of the value you're accessing is out of the range of the array. You are trying to access index 5 in an empty/having less element array, or non initialised array that's why it is giving you "outOfBounds" in cellForRowAtIndexPath.
Would it be possible that cellForRowAtIndexPath is called while the dataSource is being updated?
Yes, cellForRowAtIndexPath will always be called when you're going to see a new tableview cell for example when you're scrolling the tableview Or in case you've added some kind of notification added to your datasource or by reloading the tableview.
You can put a break point at cellForRowAtIndexPath and check the stack trace maybe you get something that causes the tableview to reload.
Try to count from self.tableData in return of numberOfRowsInSection methods. Like
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.tableData count];
}
pass array count in numberOfRowsInSection of tableView method.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return array.count;
}
Your condition
if (indexPath.row > [self.tableData count] - 1 || ![self.tableData isValidArray])
is wrong. If there is 5 elements, the last indexPath.row will be index 4 so condition with real values will be:
if (4 > 5 - 1) --> if 4 > 4
So the valid condition is:
if (indexPath.row >= [self.tableData count] - 1)
But with correct condition you will have crash on:
return nil
Because obvisously your data source is different than table data source. Your model data source should be always same as table data source.
I've viewed all of the other questions on this topic and they seem to have issues that do not pertain to my code. I've struggled with this for a while and am hoping that another set of eyes will see where I have gone wrong. I have put breakpoints in various areas of the code. There is a breakpoint with NSLog(#"number of rows, %lu",(unsigned long)self.eventContent.count); in the "TableView numberOfRowsInSection" Section that returns: "number of rows,3". I also have a breakpoint in the "tableView cellForRowAtIndexPath" Section with NSLog(#"cellForRowAtIndexPath. %lu",(long)indexPath.row); which returns:
"cellForRowAtIndexPath. 0"
"cellForRowAtIndexPath. 1"
The error occurs at 1 on the line beginning with cell.titleLabel.text. When I take out the comments on the NSLogs following, I can see that the first cell generates o.k.
Can someone please direct me to where else I might look?
So thanking you in advance...
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"number of rows, %lu",(unsigned long)self.eventContent.count);
return self.eventContent.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"eventCell";
EQCalendarCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Get the event at the row selected and display its title
NSLog(#"cellForRowAtIndexPath. %lu",(long)indexPath.row);
cell.titleLabel.text = [[[eventContent objectAtIndex:indexPath.section]objectForKey:#"title"]objectAtIndex:indexPath.row]; //Fails here
cell.notesLabel.text = [[[eventContent objectAtIndex:indexPath.section]objectForKey:#"notes"]objectAtIndex:indexPath.row];
cell.startTimeLabel.text = [[[eventContent objectAtIndex:indexPath.section]objectForKey:#"startTime"]objectAtIndex:indexPath.row];
cell.endTimeLabel.text = [[[eventContent objectAtIndex:indexPath.section]objectForKey:#"endTime"]objectAtIndex:indexPath.row];
return cell;
In number of rows in section you're using the self.eventsList array, whereas in your cellForRow method you're asking for the objectAtIndex: of the eventContent array. Chances are you messed up the two, because eventContent clearly does not have as many rows as the eventsList
I have five sections in my tableview.In my (section==4) I displaying from my array.When I scrolls down it will be crashing
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
my code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if (section == 4) {
return [mandArray count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.section == 4) {
[self.label setNumberOfLines:10];
[self.label setText:[NSString stringWithFormat:#"%i. %#",indexPath.row + 1,[mandArray objectAtIndex:indexPath.row]]];
[cell.contentView addSubview:label];
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.section==4){
return [mandArray count] *20;
}
}
The code mentioned is correct. I think you are modifying the mandArray while table is being loaded.
The procedure which i follow to load a table from array is like this.
First initialise the array and load contents into array.
Then load table. Also I add row count delegate based on array count.
**If I change the contents of array then I call [tableview reload]**so changes will be reflected in the table also.
I think you are modifying the table while it is loaded and not calling reload method. because row count delegate method is called only once per load of tableview. And it uses same data and tries to access data based on count. So to update this call reload method.
I have created a Universal Master Details application. I used Storyboard for the IPad and iPhone. I am actually making an HTTP request to retrieve the required data that will be presented in the master tableview. I reload the tableview data from the requestFinished method.
- (void)requestFinished:(ASIHTTPRequest *)request {
NSString *responseString = [request responseString];
ConversationDataController *dataControllerSingleton = [ConversationDataController sharedInstance];
conversationList = [responseString JSONValue];
[dataControllerSingleton setConversationList:conversationList];
[self.tableView reloadData];
}
I store the returned data in dataControllerSingleton which has an NSMutableArray property called conversationList.
In the numberOfRowsInSection, I print out the number of objects in the section based upon the fetchedResultsController. I also print out the number of values in my NSMutableArray conversationList. In numberOfSectionsInTableView I print out the number of sections.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
NSLog(#"Number OF Objects in section %lu",(unsigned long)[sectionInfo numberOfObjects]);
ConversationDataController *dataControllerSingleton = [ConversationDataController sharedInstance];
NSLog(#"ConversationList count %lu",(unsigned long)[dataControllerSingleton.conversationList count]);
return [sectionInfo numberOfObjects];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSLog(#"Number of sections: %d",[[self.fetchedResultsController sections] count]);
return [[self.fetchedResultsController sections] count];
}
So, when I use NSLog to see how many section and rows I have I get
Number of Objects in section 2
ConversationList count 46
Number of Sections 1
In my cellForRowAtIndexPath I am adding the cell text from my NSMutableArray
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:#"ConversationCell"];
[self configureCell:cell atIndexPath:indexPath];
ConversationDataController *dataControllerSingleton = [ConversationDataController sharedInstance];
cell.textLabel.text = [dataControllerSingleton.conversationList objectAtIndex:indexPath.row];
return cell;
}
So, with this setup, I see two values in the master view for both iPhone and iPad. When I select either one of these values in master view, I am taken to the detail view (which is just empty for now). This works without any errors for the two rows that are presented.
If I change numberOfRowsInSection to return the number of values in my NSMutableArray
return [self.conversationList count];
I run into errors.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
NSLog(#"Number OF Objects in section %lu",(unsigned long)[sectionInfo numberOfObjects]);
ConversationDataController *dataControllerSingleton = [ConversationDataController sharedInstance];
NSLog(#"ConversationList count %lu",(unsigned long)[dataControllerSingleton.conversationList count]);
//return [sectionInfo numberOfObjects];
return [self.conversationList count];
}
On iPhone simulator, I am presented with the 46 values in the master view. I can select any one of them and I am presented with the (empty) detail view. On the iPad simulator, if I select either one of the first two cells, I am presented with the (empty) detail view as expected. However, when I select any value beyond the first two, I get the following error;
Terminating app due to uncaught exception 'NSRangeException', reason: '*** - [_PFBatchFaultingArray objectAtIndex:]: index (2) beyond bounds (2)'
*** First throw call stack:
(0x19a5012 0x17cae7e 0x19a4deb 0x156941a 0x15e9511 0x42fe9 0x4ae285 0x4ae4ed 0xeb85b3 0x1964376 0x1963e06 0x194ba82 0x194af44 0x194ae1b 0x249b7e3 0x249b668 0x3feffc 0x40e0d 0x2ac5)
libc++abi.dylib: terminate called throwing an exception
Any assistance would be greatly appreciated. Thanks in advance.
Tim
If you are using more than one section (which it looks like you are) then delegate method
tableView:(UITableView *)tableView cellForRowAtIndexPath:
should really be handling this.
You also seem to be mixing the use of NSFetchedResultsController to work out the number of sections and rows, but then using the property self.conversionList to return the number of rows. But for which section. If you want to use Core Data then instead of using a singleton with an array, cache the data from your web server into a core data table and use that in your
- (NSFetchedResultsController *)fetchedResultsController
method.
Also you are mixing the use of self.conversionList &
ConversationDataController *dataControllerSingleton = [ConversationDataController sharedInstance];
dataControllerSingleton.conversationList
are they both the same?
Please add libz.dylib into your project . It can be added in the Build phases tab. There you have link with Binarry libraries section . Click '+' symbol and add libz.dylib to your project
I am having a crash with deleting a cell from a tableview. I am using a NSMutableArray loaded from NSUserDefaults to load the cells into the tableview.
This is the crash:
Code:
2011-09-03 18:21:06.097 App[10356:707] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit/UIKit-1906/UITableView.m:1046
2011-09-03 18:21:06.100 App[10356:707] *** 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 (3) must be equal to the number of rows contained in that section before the update (3), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
This is how I delete the rows...
Code:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
[self.cellArray objectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSMutableArray arrayWithObject:indexPath] withRowAnimation:YES];
[[NSUserDefaults standardUserDefaults] setObject:cellArray forKey:#"cellArray"];
}
This is my numberOfRowsInSection delegate method:
Code:
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
self.cellArray = [NSMutableArray array];
[self.cellArray addObjectsFromArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"cellArray"]];
if ([self.cellArray count] == 0) {
[ivstatstableView setHidden:YES];
[sortbar setEnabled:NO];
}
return [cellArray count];
}
Any idea what is wrong here?
You need to call reloadData after removing an object from your array. When you call reloadData method, your new array is updated which lets your UITableView load new cells based on the new updated data.