问题描述
我有以下方法为当前中心视图控制器选择行:
I have the following method that selects the row for the current center view controller:
- (void)_updateSelection
{
[self.tableView reloadData];
[_viewControllers enumerateKeysAndObjectsUsingBlock:^(NSString *path, UIViewController *viewController, BOOL *stop) {
if (viewController == self.revealSideViewController.rootViewController) {
NSInteger row = [self indexOfPath:path];
if (row != NSNotFound && row < [self.tableView numberOfRowsInSection:0]) {
[self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:0] animated:NO scrollPosition:UITableViewScrollPositionNone];
}
*stop = YES;
}
}];
}
如您所见,我进行了几项检查以确保所有内容均有效。根据表格视图,该行位于该部分的范围内。而且在大多数情况下,这很好。由于在调用 reloadData
时,表视图会不断失去选择,因此在需要进行更改时会调用此视图。我也在 viewWillAppear:
中称呼它。
As you can see, I have several checks to make sure everything is valid. According to the table view, the row is within the bounds of the section. And most of the time, this works just fine. Because the table view keeps loosing its selection when reloadData
is called, I call this when I need to make changes. I also call it in viewWillAppear:
. Here is where it occasionally crashes.
崩溃的输出是:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 2 beyond bounds [0 .. 0]'
*** First throw call stack:
(
0 CoreFoundation 0x041415e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x03ec48b6 objc_exception_throw + 44
2 CoreFoundation 0x040e24e6 -[__NSArrayM objectAtIndex:] + 246
3 UIKit 0x022aaa5c -[UITableView cellForRowAtIndexPath:] + 235
4 UIKit 0x022ad6f0 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1320
5 UIKit 0x022ad983 -[UITableView selectRowAtIndexPath:animated:scrollPosition:] + 63
6 The City 0x000073a2 __40-[TCMainMenuController _updateSelection]_block_invoke + 578
7 CoreFoundation 0x041cb13a __65-[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke + 106
8 CoreFoundation 0x041cb03e -[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:] + 190
9 CoreFoundation 0x0412f525 -[NSDictionary enumerateKeysAndObjectsUsingBlock:] + 53
10 The City 0x0000713c -[TCMainMenuController _updateSelection] + 220
11 The City 0x00006999 -[TCMainMenuController viewWillAppear:] + 105
12 UIKit 0x022e2bfa -[UIViewController _setViewAppearState:isAnimating:] + 419
13 UIKit 0x022e3108 -[UIViewController __viewWillAppear:] + 114
14 UIKit 0x022e40c7 -[UIViewController viewWillMoveToWindow:] + 387
15 UIKit 0x02227384 -[UIView(Hierarchy) _willMoveToWindow:withAncestorView:] + 619
16 UIKit 0x02232f60 -[UIView(Internal) _addSubview:positioned:relativeTo:] + 470
17 UIKit 0x022269ed -[UIView(Hierarchy) insertSubview:belowSubview:] + 55
18 The City 0x0034c6b4 -[PPRevealSideViewController pushViewController:onDirection:withOffset:animated:forceToPopPush:completion:] + 2260
19 The City 0x000afc9c -[TCRootViewController pushViewController:onDirection:withOffset:animated:forceToPopPush:completion:] + 428
20 The City 0x0034bc9c -[PPRevealSideViewController pushViewController:onDirection:withOffset:animated:completion:] + 236
21 The City 0x0034b8a4 -[PPRevealSideViewController pushViewController:onDirection:animated:completion:] + 212
22 The City 0x0034b7b5 -[PPRevealSideViewController pushViewController:onDirection:animated:] + 149
23 The City 0x000af832 -[TCRootViewController showMenu] + 162
24 The City 0x00009a13 +[App showMenu] + 83
25 The City 0x00008611 -[TCMainMenuController showMenu:] + 81
26 libobjc.A.dylib 0x03ed6874 -[NSObject performSelector:withObject:withObject:] + 77
27 UIKit 0x021cd0c2 -[UIApplication sendAction:to:from:forEvent:] + 108
28 UIKit 0x024a1c9b -[UIBarButtonItem(UIInternal) _sendAction:withEvent:] + 139
29 libobjc.A.dylib 0x03ed6874 -[NSObject performSelector:withObject:withObject:] + 77
30 UIKit 0x021cd0c2 -[UIApplication sendAction:to:from:forEvent:] + 108
31 UIKit 0x021cd04e -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61
32 UIKit 0x022c50c1 -[UIControl sendAction:to:forEvent:] + 66
33 UIKit 0x022c5484 -[UIControl _sendActionsForEvents:withEvent:] + 577
34 UIKit 0x022c4733 -[UIControl touchesEnded:withEvent:] + 641
35 UIKit 0x0220a51d -[UIWindow _sendTouchesForEvent:] + 852
36 UIKit 0x0220b184 -[UIWindow sendEvent:] + 1232
37 UIKit 0x021dee86 -[UIApplication sendEvent:] + 242
38 UIKit 0x021c918f _UIApplicationHandleEventQueue + 11421
39 CoreFoundation 0x040ca83f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
40 CoreFoundation 0x040ca1cb __CFRunLoopDoSources0 + 235
41 CoreFoundation 0x040e729e __CFRunLoopRun + 910
42 CoreFoundation 0x040e6ac3 CFRunLoopRunSpecific + 467
43 CoreFoundation 0x040e68db CFRunLoopRunInMode + 123
44 GraphicsServices 0x04f8b9e2 GSEventRunModal + 192
45 GraphicsServices 0x04f8b809 GSEventRun + 104
46 UIKit 0x021cbd3b UIApplicationMain + 1225
47 The City 0x000026ad main + 141
48 libdyld.dylib 0x0468270d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
使用调试器,我可以看到 -visibleCells
虽然不为空,但没有我要选择的单元格(但它应该不在屏幕上,但应该如此)。
Using the debugger, I can see that -visibleCells
, while not empty, does not have the cell I am trying to select (but it should, other than it is offscreen).
推荐答案
您的问题源自以下事实:在将控制权返回到运行循环时,会运行 -reloadData
。您现在的操作方式将导致崩溃,因为 -reloadData
直到离开该块后才执行。
Your issue stems from the fact that -reloadData
is run when you return control back to the run loop. The way you're doing it right now will cause a crash because -reloadData
isn't being performed until after you leave that block.
解决此问题的一种方法是调度要在下一个运行循环中运行的块:
One way to fix this is to dispatch a block to be run on the next run loop:
[self.tableView reloadData];
dispatch_async(dispatch_get_main_thread(), ^{
[_viewControllers enumerateKeysAndObjectsUsingBlock:^(NSString *path, UIViewController *viewController, BOOL *stop) {
if (viewController == self.revealSideViewController.rootViewController) {
NSInteger row = [self indexOfPath:path];
if (row != NSNotFound && row < [self.tableView numberOfRowsInSection:0]) {
[self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:0] animated:NO scrollPosition:UITableViewScrollPositionNone];
}
*stop = YES;
}
}];
});
See this discussion: How to tell when UITableVIew has completed ReloadData?
这篇关于调用selectRowAtIndexPath:animated:scrollPosition时崩溃:的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!