How to Understand What Is Causing a Crash Involving '_Nstouchbarfinderobservation'

Is there a way to understand what is causing a crash involving `_NSTouchBarFinderObservation`?

Turns out the culprit was Firebase Analytics.
The solution to prevent this crash was to add the FirebaseAppDelegateProxyEnabled to the info plist and give it a Boolean value of NO. Seems like SwiftUI, macOS and Firebase Analytics don't play nicely together.

Understand DispatchTime on M1 machines

The difference between Intel and ARM code is precision.

With Intel code, DispatchTime internally works with nanoseconds. With ARM code, it works with nanoseconds * 3 / 125 (plus some integer rounding). The same applies to DispatchQueue.SchedulerTimeType.

DispatchTimeInterval and DispatchQueue.SchedulerTimeType.Stride internally use nanoseconds on both platforms.

So the ARM code uses lower precision for calculations but full precision when comparing distances. In addition, precision is lost when converting from nanoseconds to the internal unit.

The exact formula for the DispatchTime conversions are (executed as integer operations):

rawValue = (nanoseconds * 3 + 124) / 125

nanoseconds = rawValue * 125 / 3

As an example, let's take this code:

let time1 = DispatchQueue.SchedulerTimeType(.init(uptimeNanoseconds: 10000))
let time2 = DispatchQueue.SchedulerTimeType(.init(uptimeNanoseconds: 10431))
XCTAssertEqual(time1.distance(to: time2), .nanoseconds(431))

It results in the calculation:

(10000 * 3 + 124) / 125 -> 240
(10431 * 3 + 124) / 125 -> 251
251 - 240 -> 11
11 * 125 / 3 -> 458

The resulting comparison between 458 and 431 then fails.

So the main fix would be to allow for small differences (I haven't verified if 42 is the maximum difference):

XCTAssertEqual(time1.distance(to: time2), .nanoseconds(431), accuracy: .nanoseconds(42))
XCTAssertEqual(time2.distance(to: time1), .nanoseconds(-431), accuracy: .nanoseconds(42))

And there are more surprises: Other than with Intel code, distantFuture and notSoDistantFuture are equal with ARM code. It has probably been implemented like so to protect from an overflow when multiplying with 3. (The actual calculation would be: 0xFFFFFFFFFFFFFFFF * 3). And the conversion from the internal unit to nanoseconds would result in 0xFFFFFFFFFFFFFFFF * 125 / 3, a value to big to be represented with 64 bits.

Furthermore I think that you are relying on implementation specific behavior when calculating the distance between time stamps at or close to 0 and time stamps at or close to distant future. The tests rely on the fact the distant future internally uses 0xFFFFFFFFFFFFFFFF and that the unsigned subtraction wraps around and produces a result as if the internal value was -1.

How can I prevent this crash when updating the Touch Bar's escape key?

Sorry not an answer, but too long for a comment.

I built a debug version for our users that experienced crashes, that swizzles the _updateEscapeKeyItem method, in an attempt to pinpoint the crash origin, which isn't visible due to the bottom of the stack being blown away by the infinite recursion.

My guess is they changed the 10.13 implementation radically (they mentioned something about "KVO running amok"), and might not look into 10.12 crashes unless they have a solid clue.

This is the quick and dirty code in you can drop in (mostly borrowed from How to swizzle a method of a private class), that stops the infinite recursion. The resulting crash reports might be more useful.

@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

Allow user customization of Touch Bar in macCatalyst

In my Swift Catalyst app (macOS 10.15.3, Xcode 11.3.1), I am able to call

NSTouchBar.isAutomaticCustomizeTouchBarMenuItemEnabled = true

in my override func makeTouchBar() method, and the "Customize Touch Bar..." menu item appears in the "View" menu tab. For the missing labels, the following works:

func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {
if identifier == yourIdentifier {
let item = NSPickerTouchBarItem(...)

item.customizationLabel = "View Segmented Control"

return item
}
return nil
}


Related Topics



Leave a reply



Submit