【问题标题】:Unusual crash with cocoa webView -elementAtPoint: (OS X)可可 webView -elementAtPoint 异常崩溃:(OS X)
【发布时间】:2015-05-01 17:31:20
【问题描述】:

我有一个webView 的子类,它覆盖- hitTest: 基本思想是,如果点击是在bo​​dy DOM 元素上,我希望webView 上的点击传递到nextResponder。方法是这样的

- (NSView *)hitTest:(NSPoint)aPoint
{
    NSDictionary *dict = [self elementAtPoint:aPoint];
    if([[dict valueForKey:@"WebElementDOMNode"] isKindOfClass:[DOMHTMLBodyElement class]])
    {
        return (NSView *)[self nextResponder];
    }

    return [super hitTest:aPoint];
}

运行时,它在elementAtPointEXC_BAD_ACCESS code=2 上崩溃

现在,它变得更奇怪了。如果我在该行断点应用程序,并在 LLDB 中执行 po [self elementAtPoint:aPoint],则 LLDB 会挂起,直到我执行 ^C。

更奇怪的是。如果我注释掉除最后一个 return 之外的所有内容,中断 return 语句,然后在 LLDB 中运行 po [self elementAtPoint:aPoint] — 我得到了我所期望的,一本很好的字典,告诉我当时关于 DOM 的所有信息。

什么可能导致这种行为?

注意:这是在 OS X 上,而不是在 iOS 上。

【问题讨论】:

    标签: objective-c macos cocoa webview


    【解决方案1】:

    什么可能导致这种行为?

    只需查看WebKit source code 中的[WebView _elementAtWindowPoint:][WebView _frameViewAtWindowPoint:] 实现即可。不幸的是,他们使用hitTest: 来确定@​​987654325@。

    就我而言,这种解决方法似乎有效:

    - (NSView *)hitTest:(NSPoint)point
    {
        if (m_hitTestEnabled)
        {
            [NSTimer scheduledTimerWithTimeInterval:0.
                                             target:self
                                           selector:@selector(hitTestDelayed:)
                                           userInfo:@[ @(point.x), @(point.y) ]
                                            repeats:NO];
        }
        return [super hitTest:point];
    }
    
    - (void)hitTestDelayed:(NSTimer *)timer
    {
        NSPoint point = NSMakePoint([[timer userInfo][0] floatValue], [[timer userInfo][1] floatValue]);
    
        m_hitTestEnabled = false;
        NSDictionary *dict = [self elementAtPoint:point];
        m_hitTestEnabled = true;
    
        if ([[dict valueForKey:@"WebElementDOMNode"] isKindOfClass:[DOMHTMLDivElement class]])
        {
            NSLog(@"divAtPoint: %@", dict);
        }
    }
    

    m_hitTestEnabledinitWith... 方法中设置为YES

    为什么要使用计时器? WebView 上的此类操作只允许在主线程中进行。因此,我们不能启动另一个线程来获取elementAtPoint: 并在“主”hitTest: 中等待其完成。也许有人会想出更好的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多