EDIT - SOLVED: the problem was when I created the string with all the objects to put into the tableview. I used the '?' to separe each object and one of those contained that character so the array broke.
[myString appendFormat:#"%#$%#$%#$%#?",
[currentCampeggioDict valueForKey:#"id"],
[currentCampeggioDict valueForKey:#"nome"], [...]
NS Array *elencoCampeggi=[myString componentsSeparatedByString:#"?"];
That's it.
I have this problem: my app receives from an URL a XML file with a list of objects. The tableview is populated by those objects. There are so many items, so I have to call several times the url, changing a parameter in it for example :
http://www.myurl.com?method=xxx&PAGE=1
http://www.myurl.com?method=xxx&PAGE=2
etc..
The last cell of the tableview contains the sentence "Click to load next 25 objects" and it changes the page number for the URL, delete itself and reload the url, adding the new objects to the tableview.
After 4 times everything works great, but when I press the cell for the fifth, an exception appears with the following text:
Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 17 beyond bounds [0 .. 16]'
Any help? Thanks.
EDIT: some code: this is the part where I delete the last cell
-(void) loadTestData {
// fill moviesArray with test data
NSInteger lastRow = [CampeggiArray count]-1;
if (lastLoadedPage > 1){
[CampeggiArray removeObjectAtIndex:lastRow];
[self.tableView reloadData];
}
[...]
Issue is because you are returning wrong row count in your tableview delegate method. You need to identify the total no of objects to be listed in the tableview and return the count in your tableview delegate method. This is not your page size.
For each hit you need to keep on appending the new objects to the already existing datasource(NSArray) and reload the table.There will be no objects in the datasource during initial hit.
I guess, you are returning 16 instead of 15 in the delegate method, so you wil get crash with exception. Don't hard code values in your delegate method, just get the total number of objects(entire set) and return the count of it.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [totalObjects count];
}
Related
I have a UICollectionView in my iOS application. I'd like to use the various insert... methods to add data, primarily for the animations provided by iOS when using these methods (instead of reloadData:).
If I try to add a section, however, I get an exception from iOS. My code is extremely straightforward:
_regions = [NSMutableArray array];
[self.collectionView reloadData];
NSLog (#"Before attempting to add section, collection view has %ld sections", [self numberOfSectionsInCollectionView:self.collectionView]);
[_regions addObject:#"First Region"];
[self.collectionView insertSections:[[NSIndexSet alloc] initWithIndex:0]];
NSLog (#"After attempting to add section, collection view has %ld sections", [self numberOfSectionsInCollectionView:self.collectionView]);
So I add an object to my _regions array, which I use to implement the data source, then I call insertSection. My first NSLog works:
2015-03-24 11:25:39.052 MyApp[63858:17968323] Before attempting to add section, collection view has 0 sections
but then iOS throws an exception:
2015-03-24 11:25:42.082 MyApp[63858:17968323] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections. The number of sections contained in the collection view after the update (1) must be equal to the number of sections contained in the collection view before the update (1), plus or minus the number of sections inserted or deleted (1 inserted, 0 deleted).'
I implement numberOfSectionsInCollectionView in pretty straightforward manner:
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return _regions.count;
}
If I reverse the calls (call insertSections before adding the string to the _regions array), I get a different exception:
2015-03-24 11:33:17.472 MyApp[63965:18001840] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to insert section 0 but there are only 0 sections after the update'
When should I modify (add an element to) _regions, relative to when I add the section to the UICollectionView?
Thanks so much for any help from experienced UICollectionView programmers . . .
in my application when i run app for first time,it work ok.but when i run again 2 two times, it crashes.
This is the error..
NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 5 beyond bounds for empty array'
Reason: You are accessing Empty array about to access object at index.
replace all places like in your code below
[arrMydata objectAtIndex:indexPath.row];
with
//1. Positive index ([anArray objectAtIndex:-NUMBERS]) will crash
//2. within the array boundary
if([arrMydata count] > 0 && [arrMydata count] > indexPath.row){
shrObj=[arrMydata objectAtIndex:indexPath.row];
}
else{
//Array is empty,handle as you needed
}
**Here You can see the non software example, which will explain this issue. Good luck! **
You array is empty, but you're trying to access an object in it. That is the problem.
Reason: According to your log, you're trying to access empty array. Just fix this by below code
if (arrMydata.count > inxexPath.row)
sharObj = [arrMydata objectAtIndex:indexPath.row]
In case this helps someone : in my case the array was not in code, but an IB outlet that was an array of 5 UIImageViews in the storyboard.
#IBOutlet var upAndDownArrowImages: [UIImageView]!
Reason for the crash was that I mistakenly deleted 1 of those UIImageViews from the Storyboard.
In my case, it Crashes for heightForRowAt indexpath, Do check this method for smooth operation.
Hope it Helps someone.
I have a MutableArray on this view called array and the object in question is detailItem, which has a property of rank (int). On this view, there's a text field displaying the rank and I want to be able to move the detailItem up and down the MutableArray by changing the rank.
So, for example let's say the detailItem has a rank of 3, which is index value of 2. If I change this in the text field to 3, I want the array to adjust and move it down one place. However, as I type in the value of rankField (the text field), it crashes the app since it automatically updates the value before I'm done editing. So, if I click on the text field and write 23 (planing on deleting the 2) or just press delete (now the value is nil) the app crashes with an uncaught exception.
Here's the code:
- (IBAction)rankFIeldTextChanged:(id)sender {
QueueMember *member = self.detailItem;
[self.array removeObjectAtIndex:self.detailItem.rank];
if (0<= [self.rankField.text intValue]<= self.array.count) {
[self.array insertObject:member atIndex:[self.rankField.text intValue]-1];
}
}
The if condition of making the text value in-between the array size and 0 seems to have no effect.
btw this is all in the detailsViewController which is connected to the main view controller via push segue. does it make more sense(or more better coding) to just set the new rank value in details and actually make the array changes in the mainviewcontroller.m?
The problem is that you are trying to do two boolean statements at once (which doesn't work). Change your if statement to something like:
if (0< [self.rankField.text intValue] && [self.rankField.text intValue] < self.array.count) {
//Insert your object here
}
else
{
//Add object here
}
Your current setup check to see if 0<= [self.rankField.text intValue], which will return true for all values greater than or equal to 0. Then it checks the result of that (YES:1, NO:0) if it's less than or equal to your array count. That will always return true if your array has anything in it. So basically your check will always return true.
Since it always returns true I could check for array object number 1000, your if statement says go for it, then I check and the array says "No way in heck!" and crashes your app.
EDIT: Updated my code snippet to take into account your array insertion line.
I'd just do this
- (IBAction)rankFIeldTextChanged:(id)sender {
QueueMember *member = self.detailItem;
[self.array removeObjectAtIndex:self.detailItem.rank];
if ((0<= [self.rankField.text intValue])&&([self.rankField.text intValue]<= self.array.count)) {
if (self.array.count >([self.rankField.text intValue]-1)){
[self.array insertObject:member atIndex:[self.rankField.text intValue]-1];
}
}
}
you are probably trying to insert at an index greater than the count of the array.
In my application, I use Core Data as well as NSFetchedResultsController. I need to use 1 table view row to display 9 records instead of 1 record. So I customise the numberOfRowsInSection
method:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
return [self numberOfRowsForNumber: [sectionInfo numberOfObjects]];
}
- (NSInteger)numberOfRowsForNumber:(NSInteger)num
{
NSInteger a = num / 9;
NSInteger b = num % 9;
return a + (b == 0 ? 0 : 1);
}
Adding the first record is OK. But when I add the second record, there is an error:
Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2903.23/UITableView.m:1330
2013-11-13 06:54:56.217 TestNSFetchedResultsController[2693:a0b] CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), 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). with userInfo (null)
Does it mean NSFetchedResultsController support 1 record to 1 row mapping only? Or is there better way to accomplish it?
This is easy to do with the TLIndexPathController class from TLIndexPathTools if you're OK with using an NSFetchedResultsController alternative. It rolls all five NSFetchedResultsController delegate methods into a single didUpdateDataModel method, so it is generally easier to work with. But more to your needs, it provides a willUpdateDataModel delegate method that lets you map your fetched managed objects into an arbitrary data model. Here is an example mapping the objects into groups of nine:
- (TLIndexPathDataModel *)controller:(TLIndexPathController *)controller willUpdateDataModel:(TLIndexPathDataModel *)oldDataModel withDataModel:(TLIndexPathDataModel *)updatedDataModel
{
NSArray *ungroupedItems = updatedDataModel.items;
NSMutableArray *groupedItems = [NSMutableArray array];
NSMutableArray *group;
for (id object in ungroupedItems) {
if (!group) {
group = [NSMutableArray arrayWithCapacity:9];
}
[group addObject:object];
if (group.count == 9 || object == [ungroupedItems lastObject]) {
[groupedItems addObject:group];
group = nil;
}
}
return [[TLIndexPathDataModel alloc] initWithItems:groupedItems];
}
Without going into too much detail about how TLIndexPathTools works (see the readme), you write your view controller code against the TLIndexPathDataModel API. So when you do the above mapping, your view controller just needs to be aware that the items in the data model are arrays of managed objects.
There are a couple of sample projects worth checking out:
The "Core Data" project demonstrates the Core Data integration
The "No Results" project demonstrates using the above delegate method to display a "no results" row anytime the data model contains zero items.
The one caveat is that TLIndexPathTools was only designed to scale to a few thousand items. So if you've got a really big data set, you might run into performance issues.
I figured it out. I just customise methods of NSFetchedResultsControllerDelegate. For example, I define customised NSFetchedResultsChangeInsert, NSFetchedResultsChangeDelete cases of didChangeObject method.
Thank #Duncan Groenewald for your reply.
I have some experience with using tableviews. This time, I tried loading it from an array (well, technically, from a dictionary, but the allKeys parameter is an NSArray), however, I just get this exception
-[__NSArrayI objectAtIndex:]: index 10 beyond bounds [0 .. 9]
Now, my array is 11 keys long, which means it would be counted as 10 (since Obj-C counts 0 as well). Here it says it's count is 9. I have tried several different methods:
Moving the initialisation of the dictionary to - (void)awakeFromNib
Creating a separate NSArray with all the keys
Just listing 11
But they all give me the exception!
Update
I noticed some of you were saying that my array is only 10 objects long, but if I set it to 10, I get one object missing:
The breakpoint tells 11...
There's no "Acceleration X" item when using 10 items, see?
And NSLogsays differently than 10, in the same method as returning the amount of rows
The fact of the matter is that your array is 10 items long. The comments above aren't saying "you should remove "Acceleration X" to make it 10 items long", they're saying "you're mistaken in your belief that your array is 11 items long".
Without seeing more code, it's difficult to say what's really going on here; but anyway, you shouldn't be using -allValues, because the ordering in that array is undefined, which makes it unsuitable for use backing a table view.
Instead, you should keep an array of the keys of the dictionary in whatever order you want them to display, and then reference _items[key] directly.
For example:
_keys =
#[
#"Red",
#"Orange",
#"Yellow",
#"Green",
#"Blue",
#"Indigo",
#"Violet"
];
_dictionary =
#{
#"Blue": #"Battle",
#"Green": #"Gave",
#"Indigo": #"In",
#"Orange": #"Of",
#"Red": #"Richard",
#"Violet": #"Vain"
#"Yellow": #"York",
};
- (NSString *)labelTextForIndexPath:(NSIndexPath *)indexPath
{
return _keys[indexPath.row];
}
- (NSString *)detailLabelTextForIndexPath:(NSIndexPath *)indexPath
{
return _dictionary[_keys[indexPath.row]];
}