【问题标题】:NSView only redraws on breakpointNSView 只在断点处重绘
【发布时间】:2015-08-09 02:38:04
【问题描述】:

我在 NSPopover 中有一个自定义视图。它应该根据用户输入进行更改,并且它会在用户第一次与其交互时进行,但在以下时间重绘失败。

我尝试将NSLog 放入-drawRect: 方法中,但在正常执行期间它不会被调用。当我尝试调试并在方法中放置断点时,它会正常调用并且应用程序可以正常工作。

每次需要重绘时,我都会显式调用视图-setNeedsDisplay: 方法。 我不明白为什么它应该有所作为。

这是更新视图状态的代码。这些方法是NSTextField 委托方法-textDidChange: 的一部分,我检查了每次用户在与弹出框关联的文本字段中键入内容时都会调用这些方法。

[tokenCloud tokensToHighlight:[NSArray arrayWithObject:completeSuggestionString]];
tokenCloud.tokens = filteredTokens;
[tokenCloud setNeedsDisplay:YES];

视图是一系列凹进的按钮。第一行更新弹出框中所有按钮的状态,第二行更新添加或删除按钮。它们都可以正常工作,因为第一次调用视图时会正确更新。我还检查了tokenCloud 中按钮的状态及其属性tokens 是否已正确更新。问题是NSView 子类tokenCloud 不会重绘,因此更改不会第二次反映在 UI 中。

这里是视图的draw方法:

- (void)drawRect:(NSRect)rect {
    [self recalculateButtonLocations];
    NSLog(@"Redrawn");
}

如果我在[self recalculateButtonLocations]; 中放置断点,则每次更新视图时都会正常调用此方法。相反,如果我让应用程序正常运行,那么在我第二次更新视图时,控制台中不会记录任何内容。如果我在 recalculateButtonLocations 方法中包含 NSLog 也是一样,第二次没有记录任何内容,这意味着该方法未被调用。

【问题讨论】:

  • 你能添加一个显示问题的最小代码示例吗?
  • 我很抱歉。我编辑了帖子并添加了代码。
  • 因为它是自定义视图,请尝试覆盖 setNeedsDisplay 以便在调用 super 之前包含日志。
  • 我无法重现该错误 - 它对我来说很好。我假设 tokenCloud 是您放置在 NSPopover 中的自定义视图,它也是文本字段委托

标签: objective-c macos cocoa


【解决方案1】:

EDIT2:对于未来的读者,很抱歉这个答案质量低下。其中大部分是无用的,有用的部分应该作为评论。我会删除它,但我觉得那是不诚实的。希望遇到此问题的任何人都可以在链接的答案中找到更多见解,其中确实包含一些关于为什么有时添加断点会改变程序流程的信息。

根据您绘制按钮的方式,使用layoutSubviewssetNeedsLayout 可能比drawRect 重新定位子视图更好。 [编辑:没有看到这是针对 Mac OS 而不是 iOS。 layout 确实等价于 layoutSubviews 并且有一个setNeedsLayout 对应于NSView,应该在其中进行子视图排列。]

如果没有更多信息,无法提供更多建议。然而,它与断点一起工作的事实很奇怪。我看不出为什么在方法调用行上设置断点会导致它被更频繁地调用;无论是否有断点,都应该调用该方法,并且似乎无法仅使用上述代码复制此错误...让我认为这是您的代码中的其他内容导致了此问题。


关于断点更改代码流的一些类似问题。也许以断点以外的方式休眠代码/添加暂停,看看它是否有效?如果确实如此,则可能表明存在以下问题之一。

断点改变代码工作方式的第一大原因是 比赛条件。基本上是这样的:

Without breakpoints:
    make some asynchronous request
    do something with response
    ERROR because request hasn't responded yet

With breakpoints:
    send some asynchronous request
    wait for user to continue
    response arrived while waiting for the continue
    do something with response
    OK!

^Niet the Dark Absol from Breakpoint changes program flow

我以前见过这个,我的猜测是事件正在发生 发布得太快,系统无法处理(因为它真的只有 每秒处理不超过 20 个关键事件)。我猜想 放入类似 usleep(100000) 的东西(将线程暂停 1/10 一秒钟)会有很大帮助。

^Dave DeLong 来自CGKeyEvent Pasting working with Breakpoints, but not without

一般表示竞态条件;你的代码依赖于线程 A 在线程 B 碰到某些东西之前完成或不完成某事 特定的状态。

^bbum 来自EXC_BAD_ACCESS, but not when using breakpoints

【讨论】:

  • 我似乎在NSView 中找不到layoutSubviews 方法。你的意思是-layout。问题在于它似乎适用于基于约束的视图,这不是我的情况。无论如何,我总是可以尝试用约束来实现它。感谢您的建议,但不幸的是 contentMode 不适用于可可中的NSViews
  • 啊,对不起。我没有看到 iOS 或 Mac OS 的标签,并认为您正在开发一个使用 UI 系列类的 iOS 应用程序(UIView 具有 contentMode 和 layoutSubviews)。对于那个很抱歉! xD
  • 没问题。无论如何,感谢您花时间提出建议。
  • 是的,没问题。奇怪的是,它可以使用断点但并非没有断点。对堆栈溢出的一些快速搜索揭示了一些其他类似的问题。也许尝试睡眠/添加暂停而不是断点?我会在我原来的帖子中添加一些类似案例的链接。
猜你喜欢
  • 1970-01-01
  • 2012-01-26
  • 2011-04-26
  • 2016-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多