NSPrintOperation附属视图中NSScrollView触控板滚动更新异常问题
这个触控板滚动延迟的问题我之前做打印预处理时也碰到过,结合你说的「鼠标正常、触控板要等手指离开才更新」的现象,大概率是线程同步导致主RunLoop被阻塞了——毕竟你把预处理逻辑放在了单独线程,很可能不小心让主线程在等待子线程的操作,而触控板的连续滚动事件刚好依赖主RunLoop的实时响应。
给你几个具体的排查和解决方向:
检查子线程是否阻塞了主队列
看看你的预处理线程里有没有用dispatch_sync同步调用主队列的代码,或者用了互斥锁导致主线程等待子线程完成。比如如果在预处理里写了dispatch_sync(dispatch_get_main_queue(), ^{...}),主RunLoop会被卡住,没法实时处理触控板的连续滚动事件,只能等同步操作结束(也就是你手指离开后,预处理的同步逻辑完成)才会更新滚动视图。把所有主队列的调用换成dispatch_async就能避免这个问题。强制所有UI操作在主线程执行
哪怕你觉得预处理没碰UI,也可能间接触发了tableView的数据源更新或者界面刷新。比如预处理后更新了tableView的数据源数组,然后直接调用[tableView reloadData]——如果这行代码在子线程执行,就会导致UI更新延迟。一定要把所有UI相关的代码(包括数据源更新后的界面刷新)放在主队列里:dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 子线程执行预处理 [self doPrePrintWork]; // 切回主线程处理UI和打印启动 dispatch_async(dispatch_get_main_queue(), ^{ // 更新数据源后刷新tableView self.dataSourceArray = newData; [self.tableView reloadData]; // 启动打印流程 [self startPrint]; }); });优化NSScrollView的滚动设置
虽然鼠标正常滚动说明基本设置没问题,但可以试试开启滚动视图的异步滚动优化:- 在Interface Builder里选中NSScrollView,勾选「Async Scrolling」选项;
- 代码里明确设置滚动方向,帮助系统优化触摸事件处理:
self.scrollView.hasVerticalScroller = YES; self.scrollView.hasHorizontalScroller = NO; self.scrollView.usesPredominantlyVerticalScrolling = YES;
排查RunLoop模式是否被修改
如果你的预处理线程里用到了CFRunLoopRunInMode之类的函数,可能会改变主RunLoop的运行模式,导致它没法及时响应触控板的触摸事件。尽量避免在子线程操作主RunLoop,确保主RunLoop一直在默认的NSDefaultRunLoopMode下运行。换用NSOperationQueue管理预处理线程
如果你是手动创建的线程,换成NSOperationQueue会更稳妥,它的线程管理更规范,不容易出现意外的阻塞:NSOperationQueue *preProcessQueue = [[NSOperationQueue alloc] init]; preProcessQueue.maxConcurrentOperationCount = 1; NSBlockOperation *preProcessOp = [NSBlockOperation blockOperationWithBlock:^{ [self doPrePrintWork]; }]; preProcessOp.completionBlock = ^{ dispatch_async(dispatch_get_main_queue(), ^{ [self.tableView reloadData]; [self startPrint]; }); }; [preProcessQueue addOperation:preProcessOp];
核心思路就是:绝对不能让主线程被任何子线程的操作阻塞,触控板的连续滚动是实时的事件流,主RunLoop一旦被卡住,就会出现「等手指离开才更新」的延迟现象。
内容的提问来源于stack exchange,提问作者uliwitness

