美好的一天,
我有一个复杂的日历控件,需要在每次选择日期项目时使用setneedslayout重新绘制。我试图在GCD块中运行它,但它从未运行过。但是,当我在主线程上运行它时setNeedsLayout运行并运行。然而,这会导致我的程序中令人讨厌的口吃/滞后,从而破坏用户体验。
我能知道可以做些什么吗?这可以在另一个线程上执行吗?我可以在另一个线程上使用NSTimer或执行选择器吗?
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
//[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
});
@try {
NSLog(@"New Thread");
if (self.selectedDate) {
[datesToReload addObject:self.selectedDate];
}
if (date) {
[datesToReload addObject:date];
}
self.selectedDate = date;
[self reloadDates:datesToReload];
[self performSelectorOnMainThread:@selector(reloadDates:) withObject:datesToReload waitUntilDone:NO];
//[self perform]
if (visible && date) {
self.monthShowing = date;
}
}
@catch (NSException *exception) {
NSLog(@"Exception = %@", exception);
}
dispatch_async(dispatch_get_main_queue(), ^{
//[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(@"Main Thread");
});
});
答案 0 :(得分:0)
所有UI更新都需要在主线程上运行,您不能从后台线程更改UI(它会产生不可预测的副作用)。
如果您遇到性能问题,则应使用Instruments
对应用进行分析,以了解处理时间并解决问题(例如,您是否真的需要重新加载所有日期以及需要重新加载的日期重要的时间?)。
答案 1 :(得分:0)
建议,使用上面的代码示例:
1)你正在调用reloadDates两次;即使视图在使用perform_selector进行第二次调用之前未成功更新,您仍然会执行两次相同的工作。仅此一项将使您从reloadData方法遇到的任何UI延迟加倍。
2)为大部分工作使用优先级较低的队列:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
if (self.selectedDate) {
[datesToReload addObject:self.selectedDate];
}
if (date) {
[datesToReload addObject:date];
}
self.selectedDate = date;
[self reloadDates:datesToReload];
if (visible && date) {
self.monthShowing = date;
}
});
在reloadDates内部,将仅 setNeedsLayout调用放入主队列异步块中。
完成后,如果仍然存在不可接受的UI延迟,则需要查看正在重绘的视图,并了解如何使其更快。仪器的Time Profiler是查看重绘事件期间CPU使用时间的第一步。