Cocoa 更新触摸栏时如何防止此崩溃';什么是逃生钥匙?

Cocoa 更新触摸栏时如何防止此崩溃';什么是逃生钥匙?,cocoa,nstouchbar,Cocoa,Nstouchbar,当最新的MacBook Pro发布时,我在我的应用程序中添加了触摸栏支持。后来,我做了各种小的改进,包括在有意义的地方定制转义键。发布更新后,当应用程序尝试更新escape密钥时,我开始收到崩溃报告 这里有一个例子: Exception Type: SIGBUS Exception Codes: BUS_ADRERR at 0x7fff54a05ff8 Crashed Thread: 0 Application Specific Information: Selector name fou

当最新的MacBook Pro发布时,我在我的应用程序中添加了触摸栏支持。后来,我做了各种小的改进,包括在有意义的地方定制转义键。发布更新后,当应用程序尝试更新escape密钥时,我开始收到崩溃报告

这里有一个例子:

Exception Type:  SIGBUS
Exception Codes: BUS_ADRERR at 0x7fff54a05ff8
Crashed Thread:  0

Application Specific Information:
Selector name found in current argument registers: objectForKey:

Thread 0 Crashed:
0   Foundation                           0x00007fffacbaea98 -[NSConcreteMapTable objectForKey:] + 21
1   Foundation                           0x00007fffacbfc019 -[NSISEngine outgoingRowHeadForRemovingConstraintWithMarker:] + 214
2   Foundation                           0x00007fffacbfbb4c -[NSISEngine removeConstraintWithMarker:] + 479
3   Foundation                           0x00007fffacbf76a6 -[NSISEngine _flushPendingRemovals] + 615
4   Foundation                           0x00007fffacbf4b06 -[NSISEngine withBehaviors:performModifications:] + 197
5   AppKit                               0x00007fffa8c83760 -[NSView(NSConstraintBasedLayout) _withAutomaticEngineOptimizationDisabled:] + 69
6   AppKit                               0x00007fffa8d129dd -[NSView(NSConstraintBasedLayout) removeConstraints:] + 276
7   AppKit                               0x00007fffa8c88f9e -[NSView(NSConstraintBasedLayout) _constraints_snipDangliesWithForce:] + 595
8   AppKit                               0x00007fffa8c82d9e -[NSView _setSuperview:] + 1076
9   AppKit                               0x00007fffa8c88945 -[NSView removeFromSuperview] + 446
10  AppKit                               0x00007fffa9593eef -[NSTouchBarEscapeKeyViewController setTouchBarItem:] + 145
11  AppKit                               0x00007fffa9176bf5 -[NSApplicationFunctionRowController _updateEscapeKeyItem] + 438
12  AppKit                               0x00007fffa9176bf5 -[NSApplicationFunctionRowController _updateEscapeKeyItem] + 438
13  AppKit                               0x00007fffa9176bf5 -[NSApplicationFunctionRowController _updateEscapeKeyItem] + 438
…
509 AppKit                               0x00007fffa9176bf5 -[NSApplicationFunctionRowController _updateEscapeKeyItem] + 438
510 AppKit                               0x00007fffa9176bf5 -[NSApplicationFunctionRowController _updateEscapeKeyItem] + 438
511 AppKit                               0x00007fffa9176bf5 -[NSApplicationFunctionRowController _updateEscapeKeyItem] + 438
为了简洁起见,我删除了大约500行,它们都是对
[NSApplicationFunctionRowController\u updateEscapeKeyItem]+438的调用

这是另一份简短的报告。这是我最常见的车祸。它实际上调用了我自己的代码,尽管我怀疑它调用的代码不是真正的问题:

Exception Type:  SIGBUS
Exception Codes: BUS_ADRERR at 0x7fff5b8c2f74
Crashed Thread:  0

Thread 0 Crashed:
0   CoreText                             0x00007fffc87d2e8d _ZNK3OTL7GCommon9NthLookupEj + 41
1   CoreText                             0x00007fffc87d658b _ZNK3OTL4GPOS12ApplyLookupsER8TRunGlueiRNS_12GlyphLookupsE + 155
2   CoreText                             0x00007fffc87d5f53 _ZN26TOpenTypePositioningEngine12PositionRunsER9SyncStateR13KerningStatus + 839
3   CoreText                             0x00007fffc8823920 _ZN14TKerningEngine14PositionGlyphsER8TRunGlue11ShapingTypePK10__CFString + 168
4   CoreText                             0x00007fffc87ddcf7 CTFontTransformGlyphs + 463
5   UIFoundation                         0x00007fffd9d2a795 __NSStringDrawingEngine + 7348
6   UIFoundation                         0x00007fffd9d315ea -[NSAttributedString(NSExtendedStringDrawing) boundingRectWithSize:options:context:] + 605
7   UIFoundation                         0x00007fffd9d31efd -[NSAttributedString(NSExtendedStringDrawing) boundingRectWithSize:options:] + 32
8   AppKit                               0x00007fffc4e711cb -[NSAttributedString(NSStringDrawingExtension) _sizeWithSize:] + 55
9   AppKit                               0x00007fffc4e710ff -[NSButtonCell(NSButtonCellPrivate) _titleSizeWithSize:] + 97
10  AppKit                               0x00007fffc4e70eab -[NSButtonCell(NSButtonCellPrivate) _alignedTitleRectWithRect:] + 235
11  AppKit                               0x00007fffc4e25162 -[NSButtonCell cellSizeForBounds:] + 918
12  AppKit                               0x00007fffc4da2a21 -[NSCell cellSize] + 68
13  AppKit                               0x00007fffc4da295a -[NSControl sizeToFit] + 53
14  AppKit                               0x00007fffc520392c +[NSButton(NSButtonConvenience) _buttonWithTitle:image:target:action:] + 421
15  AppKit                               0x00007fffc5203a05 +[NSButton(NSButtonConvenience) buttonWithTitle:target:action:] + 199
16  Deliveries                           0x0000000103b4c655 +[JUNTouchBar cancelButtonItemWithIdentifier:] (JUNTouchBar.m:75)
17  Deliveries                           0x0000000103b67e9b -[JUNEditWindowController touchBar:makeItemForIdentifier:] (JUNEditWindowController.m:183)
18  AppKit                               0x00007fffc57d7d2a __32-[NSTouchBar itemForIdentifier:]_block_invoke + 34
19  AppKit                               0x00007fffc4e71bd0 +[NSAppearance _performWithCurrentAppearance:usingBlock:] + 79
20  AppKit                               0x00007fffc57d7b9b -[NSTouchBar itemForIdentifier:] + 1158
21  AppKit                               0x00007fffc57d868e -[NSTouchBar(NSEscapeKeyReplacementOld) escapeKeyReplacementItem] + 51
22  AppKit                               0x00007fffc5250e80 -[NSApplicationFunctionRowController _updateEscapeKeyItem] + 238
23  AppKit                               0x00007fffc5250f49 -[NSApplicationFunctionRowController _updateEscapeKeyItem] + 439
24  AppKit                               0x00007fffc5250f49 -[NSApplicationFunctionRowController _updateEscapeKeyItem] + 439
25  AppKit                               0x00007fffc5250f49 -[NSApplicationFunctionRowController _updateEscapeKeyItem] + 439
…
509 AppKit                               0x00007fffc5250f49 -[NSApplicationFunctionRowController _updateEscapeKeyItem] + 439
510 AppKit                               0x00007fffc5250f49 -[NSApplicationFunctionRowController _updateEscapeKeyItem] + 439
511 AppKit                               0x00007fffc5250f49 -[NSApplicationFunctionRowController _updateEscapeKeyItem] + 439
我的
touchBar:makeItemForIdentifier:
方法如下:

- (nullable NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier {

    if ([identifier isEqualToString:JUNTouchBarItemIdentifierCancel]) {
        NSCustomTouchBarItem *item = [JUNTouchBar cancelButtonItemWithIdentifier:identifier];
        return item;
    }
    return nil;

}
下面是
cancelButtonItemWithIdentifier:
,也很简单:

+ (NSCustomTouchBarItem *)cancelButtonItemWithIdentifier:(NSString *)identifier {
    NSString *title = NSLocalizedString(@"Cancel", nil);
    NSButton *button = [NSButton buttonWithTitle:title target:nil action:@selector(cancelOperation:)];
    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:80.0];
    constraint.priority = 950;
    constraint.active = YES;
    NSCustomTouchBarItem *item = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];
    item.view = button;
    return item;
}
当然,我自己也不能复制这次崩溃。它发生在macOS 10.12.2到10.12.5的测试版中。许多报告都来自我自己测试的同一款13英寸型号。少数人在他们的碰撞报告中加入了评论,他们大多说这是在一个打开新窗口的动作之后立即发生的(因此改变了逃生键)-有人说这件事发生在一次可能会关闭窗户的行动之后。有人提到在崩溃前被绞死10秒钟,这是有道理的,因为有500次调用了相同的方法。有几个人不止一次提到过这件事,但他们当然没有留下任何联系信息,所以我没有办法跟进他们。

我知道我可以通过移除自定义的逃生钥匙来解决崩溃问题,但我不想这样做。关于如何处理这个问题,还有其他想法吗

更新:自从最初发布此消息以来,我已经更新了应用程序以删除约束,因此我创建按钮的代码现在非常简单:

+ (NSCustomTouchBarItem *)cancelButtonItemWithIdentifier:(NSString *)identifier {
    NSString *title = JUNLocalizedString(@"Cancel", nil);
    NSButton *button = [NSButton buttonWithTitle:title target:nil action:@selector(cancelOperation:)];
    NSCustomTouchBarItem *item = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];
    item.view = button;
    return item;
}

不幸的是,我仍然收到新版本的崩溃报告,具有相同的堆栈跟踪。因此,我认为问题不在于我提供的按钮。

抱歉,没有答案,但评论太长

我为经历过崩溃的用户构建了一个调试版本,该版本使用了_updateEscapeKeyItem方法,试图找出崩溃的根源,因为堆栈的底部被无限递归吹走了,所以它不可见

我的猜测是,他们从根本上改变了10.13的实现(他们提到了一些关于“KVO正在疯狂运行”)并且可能不会调查10.12崩溃,除非他们有可靠的线索

这是一段快速而肮脏的代码,您可以插入其中(大部分是从中借来的),它可以停止无限递归。生成的崩溃报告可能更有用

@interface NSObject (swizzle_touchbar_stuff)
@end

static NSInteger updateEscapeKeyItem = 0;

@implementation NSObject (swizzle_touchbar_stuff)
+ (void)load
{
    static dispatch_once_t onceToken = 0;
    dispatch_once(&onceToken, ^{
        Method original, swizzled;

        original = class_getInstanceMethod(objc_getClass("NSApplicationFunctionRowController"), NSSelectorFromString(@"_updateEscapeKeyItem"));
        swizzled = class_getInstanceMethod(self, @selector(sparkle_updateEscapeKeyItem));
        method_exchangeImplementations(original, swizzled);
    });
}

- (void)sparkle_updateEscapeKeyItem
{
    updateEscapeKeyItem++;
    NSLog(@"sparkle_updateEscapeKeyItem %ld", updateEscapeKeyItem);
    assert(updateEscapeKeyItem < 10);
    [(NSObject *)self sparkle_updateEscapeKeyItem];
    updateEscapeKeyItem--;
}

@end
@接口NSObject(swizzle\u touchbar\u stuff)
@结束
静态NSInteger updateEscapeKeyItem=0;
@实现NSObject(swizzle\u touchbar\u stuff)
+(空)荷载
{
静态分派\u once\u t onceToken=0;
一次发送(一次发送)^{
方法原发性,Swizzle;
original=class_getInstanceMethod(objc_getClass(“NSApplicationFunctionRowController”),NSSelectorFromString(@“\u updateEscapeKeyItem”);
swizzled=class_getInstanceMethod(self,@selector(sparkle_updateEscapeKeyItem));
方法交换实施文件(原件,SWIZED);
});
}
-(无效)sparkle_updateEscapeKeyItem
{
updateEscapeKeyItem++;
NSLog(@“sparkle_updateEscapeKeyItem%ld”,updateEscapeKeyItem);
断言(updateEscapeKeyItem<10);
[(NSObject*)自发光_updateEscapeKeyItem];
updateEscapeKeyItem--;
}
@结束

我想知道您是否找到了对此的解释?我也看到了,但缺少的堆栈底部让人很难理解…@duncanwilcox:我还没有找到解决方案。我目前正在讨论是删除约束以查看是否有帮助,还是现在完全删除自定义取消按钮。您是否添加了任何解释nts到您的按钮?仍然存在问题,并且没有添加任何约束。打开DTS事件,在来回一些之后,工程师提到“我刚刚与工程部确认,他们以前见过这种情况,但从未得到可复制的案例。然而,这应该在10.13中得到修正。“啊哈!非常感谢。我只是注意到,从10.13开始,我还没有收到任何撞车报告,但我尽量不抱太大希望。很高兴得到一些确认。我想这是我们可能得到的最佳答案。由于这似乎在10.13中得到了修复,我自己的解决方法是在
escapeKeyReplacementItemIdentifier
中添加一个
@可用的
复选框调用,因此自定义转义键仅在10.13或更高版本中显示。