I've tried:
- (IBAction)openSearch {
[tblSimpleTable scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
[searchBar becomeFirstResponder];
}
and
- (IBAction)openSearch {
[self.tblSimpleTable scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
[searchBar becomeFirstResponder];
}
to get the table to scroll to the top. Both work when the table is only slightly scrolled away from the top but otherwise crashes with a "beyond bounds" error.
Any ideas. I am fairly new to this. Thanks.
--Edit--
Thanks for the feedback. Here's the precise error
2010-02-15 00:49:02.010 MyApp [2935:207] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFArray objectAtIndex:]: index (0) beyond bounds (0)'
2010-02-15 00:49:02.016 MyApp [2935:207] Stack: (
861696817,
860329709,
861252493,
861252395,
845801683,
845954223,
30161,
835250561,
835249847,
834989551,
834983899,
834971003,
805539851,
805539363,
805538115,
805537449,
805560369,
861158231,
861448761,
861447005,
861059891,
861060063,
834770799,
834765939,
10065,
9980
)
terminate called after throwing an instance of 'NSException'
Program received signal: “SIGABRT”.
I don't get this problem when I scroll manually. The table is populated from an NSMutableArray. Does this help at all?
Neither of those will cause a crash on their own, so your crash is a side-effect of the scrolling and not a direct result of the code you pasted. It would help to know the exact error you're seeing, but a likely cause is that you have an NSArray and you're trying to get an element at an index too large for it (or possibly negative). It's likely that one of your table view's delegate or data source methods are the direct cause of the crash, and that scrolling is only relevant because it causes a bug there to manifest itself.
Perhaps a bit of a fudge but it works if i clear the table first:
searching=YES;
[tblSimpleTable reloadData];
[tblSimpleTable scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
for searching=yes the table is set to reload and empty array. I guess I could repopulate the table after doing this but I don't really need to in this case. I think the problem had something to do with the table cells being redrawn when they came into view to save memory.
Anyhow - for people with the same problem: reload the table with an empty array, scroll to the top, reload the table again with the old array. Hope this helps. Maybe someone will come up with a better way to do this.
Related
I'm making an iOS 6 program which downloads JSON data from a website and displays it in a table view. I added a pull to refresh method witch works fine. I can go in the settings view controller (secondViewController) and change the address, everything works. Then, I use the pull to refresh method and my tableView is reloaded. But if I reload 3 times AFTER changing the address, my app crashes. I get this error :
*** Terminating app due to uncaught exception 'NSRangeException',
reason: '*** -[__NSArrayM objectAtIndex:]: index 10 beyond bounds for empty array'
*** First throw call stack:
(0x1ca1012 0x10dee7e 0x1c430b4 0x3084 0xdd8fb 0xdd9cf 0xc61bb 0xd6b4b 0x732dd 0x10f26b0 0x229dfc0 0x229233c 0x2292150 0x22100bc 0x2211227 0x22bb333 0x22bb75f 0x1c60376 0x1c5fe06 0x1c47a82 0x1c46f44 0x1c46e1b 0x1bfb7e3 0x1bfb668 0x22ffc 0x1fbd 0x1ee5)
libc++abi.dylib: terminate called throwing an exception
What am I doing wrong ? And how can I fix that problem ? Thanks for your help !
The key design consideration that leaps out is that your retreiveData method is clearly updating the model (the citiesArray) asynchronously, which means that any interaction with the tableview while this is taking place may fail. You should never asynchronously update the actual citiesArray itself. The update to that array should happen in the main queue.
You should change retrieveData to not touch the existing citiesArray, but rather create and return a new array, and then, in the code you dispatch back to the main queue, only then replace the existing citiesArray and call reloadData, something like:
- (void)refresh:(UIRefreshControl *)refreshControl {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSArray *newCitiesArray = [self retreiveData];
dispatch_async(dispatch_get_main_queue(), ^{
if (newCitiesArray) {
// you presumably only want to reload the data if `retrieveData` was successful
citiesArray = newCitiesArray
[myTableView reloadData];
}
[refreshControl endRefreshing];
});
});
}
Clearly, this will involve some changes to retrieveData, too, but hopefully that's self explanatory. If not, update your question with that code, and we can make further suggestions. But we really shouldn't need to go there, as I suspect you understand the change that needs to take place there.
There are other, more subtle issues you might want to tackle, too, such as thinking about whether you really want to use a global queue, which is concurrent (e.g. if you hit refresh while the previous refresh going, do you really want two queries going on concurrently with your server ... because you dispatch the updates back to the main queue you won't crash, but it's inefficient, you're not guaranteed the order that they'll complete, etc.). You might also want to use NSOperationQueue in which you can write code to permit the cancellation of previous requests, etc.
But all of this is a little complicated and is of secondary concern to your main issue, the crashing. Refactoring the retrieveData code to ensure you don't touch citiesArray, itself, as outlined above, should address that.
Here is my error:
*** Assertion failure in -[PSUICollectionView _endItemAnimations], /SourceCache/UIKit_Sim/UIKit-2372/UICollectionView.m:2801
I'm calling it like this:
[self.collectionView deleteItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:1 inSection:1]]];
Why is this happening, any ideas?
Do you remove the item from your model as well? So, for example, if the number of rows, sections and the content they present is taken from a dictionary of arrays whose keys represent the sections and each array the rows, then if you delete one row with deleteItemsAtIndexPaths you're responsible to update the dictionary accordingly. UICollectionView will not do it for you.
Note that you are trying to delete index 1 from section 1. Both index and section starts at 0.
i did it like this:
NSMutableArray *forms; // datasource item data for all the cells
int indexToDelete; // Set to the index you want to delete
...
[self.collectionView performBatchUpdates:^(void){
[forms removeObjectAtIndex:indexToDelete]; // First delete the item from you model
[self.collectionView deleteItemsAtIndexPaths:#[[NSIndexPath indexPathForRow:indexToDelete inSection:0]]];
} completion:nil];
Check that your collection view is not busy with something else when you call deleteItemsAtIndexPaths: .
I experienced the same problem with insertItemsAtIndexPaths: method, and it turned out that it was caused by a bug in my code - I called [myCollectionView insertItemsAtIndexPaths:] immediately after calling [my collectionView reloadData] . So, at the moment of calling insertItemsAtIndexPaths: my collection view was reloading its data. After I fixed this bug, the problem with assertion failure has gone.
I have developed an app that in testing has worked fine but when it has could live I have had some issues with crashes when presenting Modal View Controllers. The issue is in here some where:
NSLog(#"Looks like we made it here 1");
UIViewController *mtaViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"mtaViewController"];
NSLog(#"Looks like we made it here 2");
[mtaViewController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
NSLog(#"Looks like we made it here 3");
[self presentModalViewController:mtaViewController animated:YES];
NSLog(#"Looks like we made it here 4");
and my output to the console is:
2012-06-14 09:26:24.161 appname[2013:707] Looks like we made it here 1
2012-06-14 09:26:24.165 appname[2013:707] Looks like we made it here 2
2012-06-14 09:26:24.166 appname[2013:707] Looks like we made it here 3
2012-06-14 09:26:28.866 appname[2013:707] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
*** First throw call stack:
(0x343ac8bf 0x345fc1e5 0x342f5b6b 0x6d3fd 0x6e719 0x3778e7ff 0x37798d53 0x37798cc1 0x37838339 0x3783714f 0x37891d97 0x7ce1d 0x7cd47 0x3788eaa5 0x3776a81b 0x3776ffb9 0x34ec1ba7 0x36fe0e8d 0x3437f2dd 0x343024dd 0x343023a5 0x30b86fcd 0x37783743 0x84327 0x6b468)
terminate called throwing an exception
I have set up in a function that I call when wanting to change view controllers and as you can see it makes it all the way down to "Looks like we made it here 3" so I suspect that there is an issue with line
[self presentModalViewController:mtaViewController animated:YES];
Can anyone help?
Check any array in mtaViewController, I dont see any array in your code so I'm thinking the issue is within mtaViewController. :)
Are you sure you view controller really gets initialized? Just an idea but this line
[mtaViewController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
would do nothing if mtaViewController would be nil. In Cocoa you can send messages to nil without problems. Your app only will crash later when you try to do something specific with them. Does
NSLog(#"%#", mtaViewController);
tell you something useful? Please make also sure you connected everything in IB that has to be connected (if you aren't working everything out in raw code).
By the way. This is deprecated. Use
presentViewController:animated:completion:
instead.
First of all Im going to show you the error I am getting, then I will try to explain what I am doing to get this error etc
2011-11-02 10:17:57.665 code[1327:707] *** Terminating app due to uncaught exception 'NSRangeException', reason: '-[UITableView scrollToRowAtIndexPath:atScrollPosition:animated:]: section (0) beyond bounds (0).'
*** First throw call stack:
(0x31fe88bf 0x31d581e5 0x31fe87b9 0x31fe87db 0x32b6df1f 0x29c9b 0x32ae26b5 0x32b3daf1 0x32afed21 0x32afea71 0x32afe78b 0x32afe4ff 0x32ab581b 0x32abafb9 0x3193aba7 0x3273be8d 0x31fbb2dd 0x31f3e4dd 0x31f3e3a5 0x3204afed 0x32ace743 0x35a1 0x301c)
terminate called throwing an exception(gdb)
This is what I am doing to get this error.
Any time that I enter the subview with the dataset of indexpath[0,1] for the second time the app will throw this error.
This is the code where the error happen.
subview.m
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
//Center previously selected cell to center of the screen
[self.tableView reloadData];
[self.tableView scrollToRowAtIndexPath:oldCheckedIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:NO]; //happens on this line
}
and this is the output from that error.
What should I be looking at.. I dont really know whats good or bad from this.
Whats really frustrating is that if I go in and out of IndexPath [0,0] from the main view or any of the other ones it works fine and there is never a problem with this app..
I am hoping someone can help me, or at the very least give me an idea of what the problem might be or where.
I had a similar problem in my project where I was deleting objects from my datasource and then immediately calling [self.tableview reloadData];
What I did to solve the issue was call:
dispatch_after(DISPATCH_TIME_NOW, dispatch_get_main_queue(), ^(void){
[self.tableView reloadData];
});
This basically calls reloadData in the next run loop. You can do a similar thing using performSelector:afterDelay.
So my suggestion is try calling:
dispatch_after(DISPATCH_TIME_NOW, dispatch_get_main_queue(), ^(void){
[self.tableView scrollToRowAtIndexPath:oldCheckedIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
}
Note: You don't need to actually have a delay time specified, these 2 techniques force the method to be called at the start of the next run loop.
I am populating a UITableViewController with an NSFetchedResultsController with results creating sections that populate section headers and a section index. I am using the following method to populate the section index:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [fetchedResultsController_ sectionIndexTitles];
}
and now I've run into a problem. When I add a new element to the NSManagedObjectContext associated with the NSFetchedResultsController, the new element is saved and appropriately displayed as a cell in the UITableView ... except for one thing. If the new element creates a new SECTION, the new section index does not show up in the right hand margin unless I pop the UINavigationController's stack and reload the UITableViewController.
I have conformed to the NSFetchedResultsControllerDelegate's interface and manually invoke
[self.tableView reloadSectionIndexTitles];
at the end of both these delegate methods:
controller:didChangeSection...
controller:didChangeObject...
and while I can debug and trace the execution into the methods and see the reload call invoked, the UITableView's section index never reflects the section changes.
Again, the data shows up - new sections are physically visible (or removed) in the UITableView but the section indexes are not updated.
Am I missing something?
Looks like this is a bug we're all having. See http://iphonedevelopment.blogspot.com/2009/11/i-know-youre-tired-of-hearing-about.html for what looks to me like a fairly nasty too-many-lines-of-code solution. I went with this:
- (void)viewWillAppear:(BOOL)animated; {
// This is a dumb hack required by this bug: http://iphonedevelopment.blogspot.com/2009/11/i-know-youre-tired-of-hearing-about.html
[self.tableView reloadData];
}
It may be inefficient but unless you have reams and reams of data it probably won't do any harm. And it's only 1 line of code. So, when apple fixes their bug, you can easily take it out.
Question already 2 months old, but I ran into the same problem today. It seems like -reloadSectionIndexTitles is not working at all, so I tried a couple of potential hacks which of the following works for me:
#implementation UITableView (JKAdditions)
- (UIView *)indexView {
Class indexClass = NSClassFromString(#"UITableViewIndex");
for(UIView *subview in self.subviews){
if([subview isKindOfClass:indexClass]) return subview;
}
return nil;
}
- (void)reloadSectionIndexTitles {
UIView *indexView = [self indexView];
[indexView performSelector:#selector(setTitles:) withObject:[self.dataSource sectionIndexTitlesForTableView:self]];
[indexView setNeedsDisplay];
}
#end
I really have no idea if Apple would reject your App because of this hack, but it seems like the only option for me. Reloading the whole tableView is simply not what I want since I then have to deal with all kinds of animation problems.
I hope this helps anyone having the same problems!
To combine the accepted answer with Alex Reynolds's answer with the delay, just call reloadData with a delay that corresponds to the animation duration, so 0.4 or 0.3 seconds.
In my case, I stick the delayed method call into controller:didChangeSection:atIndex:forChangeType: (it's a Core Data app).
The result, when a section is added or deleted, is the standard animation of the cell, followed by the index being updated when the data is reloaded.
It's ugly and makes me cringe, but I am okay with the result. I also submitted a bug to Apple, #8589547.
Try putting it at the end of -controllerDidChangeContent:, somewhere after [self.tableView endUpdates].
Another thing I do (that works for me, can't guarantee it will work for you) is perform a selector after a very short delay, e.g.:
[self performSelector:(#selector(refreshSectionIndex)) withObject:nil afterDelay:0.2];
// ...
- (void) refreshSectionIndex {
[self.tableView reloadSectionIndexTitles];
}
Core Data and NSFetchedResultsController in particular seem buggy as hell, where delegate table view updates get out of sync with the fetched data, causing the application to crash. I really hope Apple is taking steps to fix the bugs in these frameworks in the 4.0 SDK. It's pretty frustrating.