应钛诱饵的要求,这是我解决此问题的方法:
我有一个UIViewController
子类,NSTimer
它每秒执行一次,检查底层数据源中是否有UITableView
表明需要调用的更改-reloadData
。所以,我在那个子类中添加了:
@property (BOOL) IsAnimating;
我最初将其设置为,NO
如果isAnimating
属性设置为YES
,则NSTimer
“短路”并跳过其正常处理。
所以,当我想运行这个UITableView
动画时,我将isAnimating
属性设置为YES
并运行动画。
然后,我安排一个选择器在未来运行 1 秒,然后重置isAnimating
为NO
. 然后NSTimer
将继续触发并会看到一个isAnimating
of NO
(很可能在随后的第二次调用中-codeTimerFired
),然后找到数据源更新,开始调用reloadData
.
这是暂停NSTimer
处理和调度UITableView
动画的代码:
// currentIndex and newIndex have already been calculated as the data item's
// original and destination indices (only 1 section in UITableView)
if (currentIndex != newIndex) {
// This item's index has changed, so animate its movement
NSIndexPath *oldPath = [NSIndexPath indexPathForRow:currentIndex inSection:0];
NSIndexPath *newPath = [NSIndexPath indexPathForRow:newIndex inSection:0];
// Set a flag to disable data source processing and calls to [UITableView reloadData]
[[self Owner] setIsAnimating:YES];
// I haven't tested enough, but some documentation leads me to believe
// that this particular call (-moveRowAtIndexPath:toIndexPath:) may NOT need
// to be wrapped in a -beginUpdates/-endUpdates block
[[[self Owner] InstructionsTableView] beginUpdates];
// These lines move the item in my data source
[[[MMAppDelegate singleton] CurrentChecklist] removeObject:[self CellTask]];
[[[MMAppDelegate singleton] CurrentChecklist] insertObject:[self CellTask] atIndex:newIndex];
// This code is the UITableView animation
[[[self Owner] InstructionsTableView] moveRowAtIndexPath:oldPath toIndexPath:newPath];
// Conclude the UITableView animation block
[[[self Owner] InstructionsTableView] endUpdates];
// Schedule a call to re-enable UITableView animation
[[self Owner] performSelector:@selector(setIsAnimating:) withObject:@(NO) afterDelay:1.0];
} else {
// This location hasn't changed, so just tell my owner to reload its data
[[[self Owner] InstructionsTableView] reloadData];
}
这是NSTimer
方法(注意它是如何退出 if的isAnimating == YES
):
- (void)codeTimerFired {
// This is a subclass of a template subclass...
// super actually has work to do in this method...
[super codeTimerFired];
// If we're in the middle of an animation, don't update!
if ([self IsAnimating]) {
return;
}
// Other data source processing...
// local BOOL to check whether underlying data source has changed
BOOL shouldUpdate = NO;
// code to check if underlying data source has changed...
// ******************************************************
// [CODE REMOVED]
// ******************************************************
// If the underlying data source has changed, update the UITableView
if (shouldUpdate) {
[self reloadTableView]; // <--- This is the main line I wanted to prevent
// since the code that fired to cause the
// UITableView animation will ALWAYS cause
// the underlying data source to change such
// that this line would fire.
}
}