2017-04-19 87 views
0

当最新的MacBook Pro推出时,我将Touch Bar支持添加到我的应用程序中。后来我做了各种小的改进,包括自定义的转义键在哪里有意义。发布更新后,我开始在应用程序尝试更新转义键时收到崩溃报告。如何在更新Touch Bar的退出键时防止此崩溃?

这里有一个例子:

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 _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的beta版本中。许多报告来自我正在测试的同一个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; 
} 

不幸的是,我仍然得到来自新版本的崩溃报告,具有相同的堆栈跟踪。所以我不认为问题出在我提供的按钮上。

+0

我想知道您是否找到了解释?我也看到了它,但缺少的底部堆栈使得很难弄清楚...... – duncanwilcox

+0

@duncanwilcox:我还没有找到解决方案。我目前正在讨论移除约束条件以查看是否有帮助,或者现在只是完全删除自定义取消按钮。你是否添加了任何约束到你的按钮? – robotspacer

+0

仍然有问题,并没有添加约束。 – duncanwilcox

回答

1

对不起,没有答案,但太长的评论。

我为我们的用户构建了一个调试版本,该版本遇到了崩溃问题,它调整了_updateEscapeKeyItem方法,尝试查明崩溃原点,由于堆栈的底部被无限递归吹掉而不可见。我猜他们是从根本上改变了10.13的实现(他们提到了一些关于“KVO正在运行的流言蜚语”),并且可能不会查看10.12崩溃,除非他们有一个确凿的线索。

这是快速和脏的代码,你可以放在(主要是从How to swizzle a method of a private class借用),即停止无限递归。由此产生的崩溃报告可能会更有用。

@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 
+0

我怀疑这是我们可能得到的最佳答案。由于这个问题似乎在10.13中得到解决,我自己的解决方法是在调用'escapeKeyReplacementItemIdentifier'时添加'@ available'检查,所以自定义转义键只在10.13或更高版本中显示。 – robotspacer