NSRunLoop 因 NSTimer 和任何输入而冻结

发布于 2024-10-11 03:31:18 字数 332 浏览 0 评论 0原文

由于某种原因,当我按下(单击并按住)任何控件时,我的应用程序中的 NSTimer 会冻结并且不会触发,直到我释放鼠标按钮。当我按下鼠标时它根本不会触发。这在短时间内没问题,但如果我打开弹出菜单或下拉组合框,它也会冻结。

我不确定是否有什么我错过的事情,但这似乎是不正确的行为。

我希望能够单击 NSPopUpButtonCell 的向下箭头(甚至单击并按住 NSTableView),而不会使整个 NSTimer 冻结(这会重绘 NSView)。

任何意见/建议将不胜感激。

NSTimer 以 NSDefaultRunLoopMode 模式添加到 currentRunLoop 中。

For some reason when I push down (click and hold) on any control, the NSTimer in my App freezes and does not fire until I release the mouse button. It simply does not fire while I have the mouse pressed. This is fine for short periods, but it also freezes if I have a popup menu open, or a combobox dropped down.

I'm not sure if there is something I missed, but it seems like this is incorrect behavior.

I want to be able to click the down arrow of an NSPopUpButtonCell (or even click and hold an NSTableView) without the entire NSTimer freezing (which redraws an NSView).

Any comments / suggestions would be appreciated.

The NSTimer is added to the currentRunLoop with mode NSDefaultRunLoopMode.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

得不到的就毁灭 2024-10-18 03:31:18

当鼠标按下时,运行循环位于 NSEventTrackingRunLoopMode。因此,在运行循环返回到适当的模式之前,EventTracking 事件队列接收到的任何事件都不会得到服务。

解决这个问题的方法是将计时器添加到两种模式(默认和事件跟踪)的运行循环中。

While the mouse is down, the run loop is in the NSEventTrackingRunLoopMode. Therefore, any event that's not received onto the EventTracking event queue won't be serviced until the runloop returns to the appropriate mode.

The way around this is to add the timer to the runloop for both modes (default and event tracking).

白芷 2024-10-18 03:31:18

无需将两个或多个计时器添加到不同的运行循环或使用多线程(因为您将无法从另一个线程更新 UI),只需将计时器添加到 NSRunLoopCommonModes 即可:

NSTimer *myTimer = [NSTimer timerWithTimeInterval:RefreshInterval target:self selector:@selector(doWork) userInfo:nil repeats:YES];
  [[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes];

Instead of adding two or more timers to different runloops or using multithreading (as you won't then be able to update the UI from another thread) simply add the timer to the NSRunLoopCommonModes:

NSTimer *myTimer = [NSTimer timerWithTimeInterval:RefreshInterval target:self selector:@selector(doWork) userInfo:nil repeats:YES];
  [[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes];
━╋う一瞬間旳綻放 2024-10-18 03:31:18

假设您只处理应用程序中的一个线程,那么您所描述的内容是完全符合预期的。默认情况下,NSTimer 会添加到当前的 NSRunLoop 中,在您的情况下,它还负责处理 UI 交互。当它与处理 UI 交互相关时,它无法检查您的计时器并“触发”它。

一个解决方案是使用多线程以避免这种束缚。这是关于这个主题的一篇很好的博客文章:http://blog.narent.com/?p=21

编辑:请参阅 Dave 的帖子,了解替代(且更优雅的 IMO)解决方案

另请参阅:

Assuming you're just dealing with one thread in your application, what you described is perfectly expected. By default, NSTimer's are added to the current NSRunLoop which, in your case, is also responsible for dealing with UI interaction. When it gets tied up with handling UI interaction, it can't check your timer and "fire" it.

A solution is to use multi-threading so as to avoid this tie-up. Here's a nice blog post on this very subject: http://blog.narent.com/?p=21

EDIT: See Dave's post for an alternative (and more elegant IMO) solution

Also see:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文