How can I solve unconditionallyBridgeFromObjectiveC crash when storing a String value? (WKInterfaceDevice.current().name)

Viewed 1436

I'm getting a unconditionallyBridgeFromObjectiveC crash in an Apple Watch app out in the wild. I'm not able to replicate it locally, and haven't ever encountered it on a test device through regular use. Here's the info about the exception:

Exception Type:  EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x00000000224c58b0
Termination Signal: Trace/BPT trap: 5
Termination Reason: Namespace SIGNAL, Code 0x5
Terminating Process: exc handler [653]

The crash reports show it's happening on the second line of this code:

let name: String
name = WKInterfaceDevice.current().name

(I have these on separate lines for better readability in my code)

I'm not very family with Objective-C or how things can fail related to Objective-C values, but from what I've found around the Internet, here's my guess:

Even though the API says that WKInterfaceDevice.current().name is a String instead of String?, name is somehow actually a nil value in some cases.

As a possible solution, I'm thinking that instead of name: String I should use name: String? and then make sure it's non-nil later. Does this make sense? Would that help with the issue, or would it be possible that it still crashes from trying to store WKInterfaceDevice.current().name in a constant of type String?? Is there some other kind of safety check I should be doing on WKInterfaceDevice.current().name first?

This crash is not happening much (on at least 7 devices out of ~5000 in about 5 days) but it's the most frequent crash in the newest version of my app, so I'm trying to use it as a learning opportunity to make my app more robust. I guess maybe it could be an issue in WatchKit rather than a problem with my code? Or something that could only be checked and solved with Objective-C?

Stack Trace:

Hardware Model:      Watch5,2
Version:             1 (2020.29)
AppVariant:          1:Watch5,2:6
Code Type:           ARM (Native)
Role:                Foreground
Parent Process:      launchd [1]


Date/Time:           2020-05-28 14:32:42.6998 +0900
Launch Time:         2020-05-28 14:32:07.0000 +0900
OS Version:          Watch OS 6.2.5 (17T608)
Release Type:        User
Baseband Version:    n/a
Report Version:      104

Exception Type:  EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x00000000224c58b0
Termination Signal: Trace/BPT trap: 5
Termination Reason: Namespace SIGNAL, Code 0x5
Terminating Process: exc handler [653]
Triggered by Thread:  5

Thread 0 name:
Thread 0:
0   libsystem_kernel.dylib          0x21fdb134 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x21fda604 mach_msg + 72 (mach_msg.c:103)
2   libdispatch.dylib               0x21e5a49c _dispatch_mach_send_and_wait_for_reply + 580 (mach.c:830)
3   libdispatch.dylib               0x21e5a858 dispatch_mach_send_with_result_and_wait_for_reply + 52 (mach.c:2006)
4   libxpc.dylib                    0x220bd150 xpc_connection_send_message_with_reply_sync + 228 (connection.c:829)
5   CoreFoundation                  0x2239cfec __99-[CFPrefsPlistSource sendFullyPreparedMessage:toConnection:settingValues:forKeys:count:retryCount:]_block_invoke + 56 (CFPrefsPlistSource.m:933)
6   CoreFoundation                  0x22353cb4 -[_CFXPreferences withConnectionForRole:performBlock:] + 48 (CFXPreferences.m:1330)
7   CoreFoundation                  0x2239cf88 -[CFPrefsPlistSource sendFullyPreparedMessage:toConnection:settingValues:forKeys:count:retryCount:] + 188 (CFPrefsPlistSource.m:962)
8   CoreFoundation                  0x2239d2c4 -[CFPrefsPlistSource sendMessageSettingValues:forKeys:count:] + 304 (CFPrefsPlistSource.m:994)
9   CoreFoundation                  0x2239c0f4 -[CFPrefsPlistSource alreadylocked_setPrecopiedValues:forKeys:count:from:] + 948 (CFPrefsPlistSource.m:397)
10  CoreFoundation                  0x2249ac9c -[CFPrefsSource setValues:forKeys:count:copyValues:removeValuesForKeys:count:from:] + 392 (CFPrefsSource.m:771)
11  CoreFoundation                  0x2249affc -[CFPrefsSource setValues:forKeys:count:copyValues:from:] + 36 (CFPrefsSource.m:793)
12  CoreFoundation                  0x223d74e4 -[CFPrefsSearchListSource alreadylocked_setPrecopiedValues:forKeys:count:from:] + 968 (CFPrefsSearchListSource.m:738)
13  CoreFoundation                  0x2249ac9c -[CFPrefsSource setValues:forKeys:count:copyValues:removeValuesForKeys:count:from:] + 392 (CFPrefsSource.m:771)
14  CoreFoundation                  0x2249affc -[CFPrefsSource setValues:forKeys:count:copyValues:from:] + 36 (CFPrefsSource.m:793)
15  CoreFoundation                  0x2234fc04 -[CFPrefsSource setValue:forKey:from:] + 64 (CFPrefsSource.m:799)
16  CoreFoundation                  0x224a3008 __76-[_CFXPreferences setValue:forKey:appIdentifier:container:configurationURL:]_block_invoke + 64 (CFXPreferences.m:795)
17  CoreFoundation                  0x223d9540 __108-[_CFXPreferences(SearchListAdditions) withSearchListForIdentifier:container:cloudConfigurationURL:perform:]_block_invoke + 372 (CFPrefsSearchListSource.m:1719)
18  CoreFoundation                  0x2234c6bc -[_CFXPreferences(SearchListAdditions) withSearchListForIdentifier:container:cloudConfigurationURL:perform:] + 340 (CFPrefsSearchListSource.m:68)
19  CoreFoundation                  0x2234f674 -[_CFXPreferences setValue:forKey:appIdentifier:container:configurationURL:] + 108 (CFXPreferences.m:791)
20  CoreFoundation                  0x224a619c _CFPreferencesSetAppValueWithContainerAndConfiguration + 132 (CFXPreferences.m:1853)
21  Foundation                      0x22e55a4c -[NSUserDefaults(NSUserDefaults) setObject:forKey:] + 64 (NSUserDefaults.m:226)
22  My App Name                     0x04a55320 specialized static NSUserDefaults.lastSentToPhone.setter + 272 (UserDefaults.swift:423)
23  My App Name                     0x04a500ac WatchConnectivityManager.sendBatteryLevel() + 2692 (<compiler-generated>:0)
24  My App Name                     0x04a55714 @objc ExtensionDelegate.applicationWillEnterForeground() + 188 (ExtensionDelegate.swift:32)
25  WatchKit                        0x34d21654 __80-[SPRemoteInterface applicationWillEnterForeground:withVisibleViewControllerID:]_block_invoke_2 + 128 (SPRemoteInterface.m:3668)
26  WatchKit                        0x34d40910 -[SPRemoteInterface performAfterApplicationDidFinishLaunching:] + 56 (SPRemoteInterface.m:3713)
27  WatchKit                        0x34d215c8 __80-[SPRemoteInterface applicationWillEnterForeground:withVisibleViewControllerID:]_block_invoke + 80 (SPRemoteInterface.m:3666)
28  WatchKit                        0x34d3ef08 spUtils_dispatchAsyncToMainThread + 40 (SPUtils.m:347)
29  WatchKit                        0x34d21444 -[SPRemoteInterface applicationWillEnterForeground:withVisibleViewControllerID:] + 212 (SPRemoteInterface.m:3665)
30  WatchKit                        0x34d2135c -[SPRemoteInterface appWillEnterForeground:withVisibleViewControllerID:] + 60 (SPRemoteInterface.m:4535)
31  WatchKit                        0x34d21280 __75-[SPExtensionConnection appWillEnterForegroundWithVisibleViewControllerID:]_block_invoke + 320 (SPExtensionConnection.m:1669)
32  WatchKit                        0x34d3d64c -[SPExtensionConnection performOnSendQueue:syncIfUnsuspended:] + 564 (SPExtensionConnection.m:0)
33  WatchKit                        0x34d2111c -[SPExtensionConnection appWillEnterForegroundWithVisibleViewControllerID:] + 112 (SPExtensionConnection.m:1667)
34  WatchKit                        0x34d21010 -[SPApplicationDelegate applicationWillEnterForeground:] + 264 (SPApplicationDelegate.m:670)
35  UIKitCore                       0x3f3a7ca4 -[UIApplication _sendWillEnterForegroundCallbacks] + 164 (UIApplication.m:10680)
36  UIKitCore                       0x3ec6c630 __101-[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:]_block_invoke_2 + 1748 (_UISceneLifecycleMultiplexer.m:572)
37  UIKitCore                       0x3f069a5c _UIScenePerformActionsWithLifecycleActionMask + 104 (_UISceneLifecycleState.m:109)
38  UIKitCore                       0x3ec6beb8 __101-[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:]_block_invoke + 208 (_UISceneLifecycleMultiplexer.m:501)
39  UIKitCore                       0x3ec6b8d0 -[_UISceneLifecycleMultiplexer _performBlock:withApplicationOfDeactivationReasons:fromReasons:] + 292 (_UISceneLifecycleMultiplexer.m:450)
40  UIKitCore                       0x3ec6bcc4 -[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:] + 768 (_UISceneLifecycleMultiplexer.m:500)
41  UIKitCore                       0x3ec6b564 -[_UISceneLifecycleMultiplexer uiScene:transitionedFromState:withTransitionContext:] + 336 (_UISceneLifecycleMultiplexer.m:406)
42  UIKitCore                       0x3ec6fb50 __186-[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:]_block... + 188 (_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction.m:102)
43  UIKitCore                       0x3efa7548 +[BSAnimationSettings(UIKit) tryAnimatingWithSettings:actions:completion:] + 804 (BSAnimationSettings+UIKit.m:50)
44  UIKitCore                       0x3f0827dc _UISceneSettingsDiffActionPerformChangesWithTransitionContext + 244 (_UISceneSettingsDiffAction.m:43)
45  UIKitCore                       0x3ec6f920 __186-[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:]_block... + 136 (_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction.m:87)
46  UIKitCore                       0x3f0826d8 _UISceneSettingsDiffActionPerformActionsWithDelayForTransitionContext + 100 (_UISceneSettingsDiffAction.m:35)
47  UIKitCore                       0x3ec6f78c -[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:] + 376 (_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction.m:85)
48  UIKitCore                       0x3eaf2b78 __64-[UIScene scene:didUpdateWithDiff:transitionContext:completion:]_block_invoke + 640 (UIScene.m:1340)
49  UIKitCore                       0x3eaf1720 -[UIScene _emitSceneSettingsUpdateResponseForCompletion:afterSceneUpdateWork:] + 236 (UIScene.m:1073)
50  UIKitCore                       0x3eaf28ac -[UIScene scene:didUpdateWithDiff:transitionContext:completion:] + 220 (UIScene.m:1317)
51  UIKitCore                       0x3efc7c8c -[UIApplicationSceneClientAgent scene:handleEvent:withCompletion:] + 464 (UIApplicationSceneClientAgent.m:80)
52  PepperUICore                    0x2ebc2d94 -[PUICApplicationSceneClientAgent scene:handleEvent:withCompletion:] + 804 (PUICApplicationSceneClientAgent.m:156)
53  CarouselUIServices              0x32abcbec -[CUISWatchKitApplicationSceneClientAgent scene:handleEvent:withCompletion:] + 276 (CUISWatchKitApplicationSceneClientAgent.m:80)
54  FrontBoardServices              0x25ea1660 -[FBSSceneImpl updater:didUpdateSettings:withDiff:transitionContext:completion:] + 528 (FBSSceneImpl.m:551)
55  FrontBoardServices              0x25ec5914 __88-[FBSWorkspaceScenesClient sceneID:updateWithSettingsDiff:transitionContext:completion:]_block_invoke_2 + 120 (FBSWorkspaceScenesClient.m:356)
56  FrontBoardServices              0x25eab12c -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 232 (FBSWorkspace.m:357)
57  FrontBoardServices              0x25ec5848 __88-[FBSWorkspaceScenesClient sceneID:updateWithSettingsDiff:transitionContext:completion:]_block_invoke + 184 (FBSWorkspaceScenesClient.m:355)
58  libdispatch.dylib               0x21e44fc0 _dispatch_client_callout + 16 (object.m:495)
59  libdispatch.dylib               0x21e47cac _dispatch_block_invoke_direct + 248 (queue.c:466)
60  FrontBoardServices              0x25ee9b44 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 40 (FBSSerialQueue.m:173)
61  FrontBoardServices              0x25ee9810 -[FBSSerialQueue _queue_performNextIfPossible] + 412 (FBSSerialQueue.m:216)
62  FrontBoardServices              0x25ee9d94 -[FBSSerialQueue _performNextFromRunLoopSource] + 28 (FBSSerialQueue.m:247)
63  CoreFoundation                  0x223ee2f8 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24 (CFRunLoop.c:1922)
64  CoreFoundation                  0x223ee250 __CFRunLoopDoSource0 + 80 (CFRunLoop.c:1956)
65  CoreFoundation                  0x223ed9f0 __CFRunLoopDoSources0 + 184 (CFRunLoop.c:1992)
66  CoreFoundation                  0x223e8adc __CFRunLoopRun + 772 (CFRunLoop.c:2882)
67  CoreFoundation                  0x223e84d0 CFRunLoopRunSpecific + 424 (CFRunLoop.c:3192)
68  GraphicsServices                0x25984358 GSEventRunModal + 160 (GSEvent.c:2246)
69  UIKitCore                       0x3f392fac UIApplicationMain + 1756 (UIApplication.m:4820)
70  libxpc.dylib                    0x220d9bdc _xpc_objc_main.cold.3 + 208
71  libxpc.dylib                    0x220c5ccc _xpc_objc_main + 212 (main.m:0)
72  libxpc.dylib                    0x220c82b0 xpc_main + 152 (init.c:1384)
73  Foundation                      0x22e51738 -[NSXPCListener resume] + 160 (NSXPCListener.m:276)
74  PlugInKit                       0x2bdb40a8 -[PKService run] + 396 (PKService.m:165)
75  WatchKit                        0x34d39e94 WKExtensionMain + 60 (main.m:19)
76  libdyld.dylib                   0x21e80f48 start + 4

Thread 1:
0   libsystem_pthread.dylib         0x22081800 start_wqthread + 0

Thread 2:
0   libsystem_pthread.dylib         0x22081800 start_wqthread + 0

Thread 3 name:
Thread 3:
0   libsystem_kernel.dylib          0x21fdb134 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x21fda604 mach_msg + 72 (mach_msg.c:103)
2   CoreFoundation                  0x223edb5c __CFRunLoopServiceMachPort + 148 (CFRunLoop.c:2575)
3   CoreFoundation                  0x223e8c40 __CFRunLoopRun + 1128 (CFRunLoop.c:2931)
4   CoreFoundation                  0x223e84d0 CFRunLoopRunSpecific + 424 (CFRunLoop.c:3192)
5   Foundation                      0x22e1638c -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 228 (NSRunLoop.m:374)
6   Foundation                      0x22e1626c -[NSRunLoop(NSRunLoop) runUntilDate:] + 88 (NSRunLoop.m:421)
7   UIKitCore                       0x3f4235f8 -[UIEventFetcher threadMain] + 152 (UIEventFetcher.m:733)
8   Foundation                      0x22f42404 __NSThread__start__ + 844 (NSThread.m:724)
9   libsystem_pthread.dylib         0x22079984 _pthread_start + 156 (pthread.c:896)
10  libsystem_pthread.dylib         0x22081814 thread_start + 8

Thread 4 name:
Thread 4:
0   libobjc.A.dylib                 0x21d8407c getMethodNoSuper_nolock(objc_class*, objc_selector*) + 168 (objc-runtime-new.mm:5813)
1   libobjc.A.dylib                 0x21d8e164 lookUpImpOrForward + 348 (objc-runtime-new.mm:6221)
2   libobjc.A.dylib                 0x21d7ad5c _objc_msgSend_uncached + 60
3   libobjc.A.dylib                 0x21d7a588 CALLING_SOME_+initialize_METHOD + 20 (objc-initialize.mm:384)
4   libobjc.A.dylib                 0x21d80140 initializeNonMetaClass + 548 (objc-initialize.mm:554)
5   libobjc.A.dylib                 0x21d814d8 initializeAndMaybeRelock(objc_class*, objc_object*, mutex_tt<false>&, bool) + 272 (objc-runtime-new.mm:2183)
6   libobjc.A.dylib                 0x21d8e2c8 lookUpImpOrForward + 704 (objc-runtime-new.mm:2199)
7   libobjc.A.dylib                 0x21d7ad5c _objc_msgSend_uncached + 60
8   WatchConnectivity               0x3616795c -[WCQueueManager onqueue_sendMessage:completionHandler:] + 64 (WCQueueManager.m:100)
9   libdispatch.dylib               0x21e43c1c _dispatch_call_block_and_release + 24 (init.c:1408)
10  libdispatch.dylib               0x21e44fc0 _dispatch_client_callout + 16 (object.m:495)
11  libdispatch.dylib               0x21e4b128 _dispatch_lane_serial_drain + 676 (inline_internal.h:2484)
12  libdispatch.dylib               0x21e4bb08 _dispatch_lane_invoke + 404 (queue.c:3863)
13  libdispatch.dylib               0x21e5501c _dispatch_workloop_worker_thread + 584 (queue.c:6445)
14  libsystem_pthread.dylib         0x2207b704 _pthread_wqthread + 276 (pthread.c:2351)
15  libsystem_pthread.dylib         0x22081808 start_wqthread + 8

Thread 5 name:
Thread 5 Crashed:
0   CoreFoundation                  0x224c58b0 _CFRelease.cold.2 + 16
1   CoreFoundation                  0x223efda4 _CFRelease + 1440 (CFRuntime.c:2041)
2   libswiftCore.dylib              0x48565aa8 String.init(_cocoaString:) + 44 (<compiler-generated>:0)
3   libswiftFoundation.dylib        0x48820d94 static String._unconditionallyBridgeFromObjectiveC(_:) + 36 (String.swift:25)
4   My App Name                     0x04a503f0 WatchConnectivityManager.getCurrentWatchInfo() + 424 (WatchConnectivityManager.swift:219)
5   My App Name                     0x04a4f798 WatchConnectivityManager.sendWatchInfo() + 368 (WatchConnectivityManager.swift:149)
6   My App Name                     0x04a508cc @objc WatchConnectivityManager.session(_:activationDidCompleteWith:error:) + 72 (WatchConnectivityManager.swift:252)
7   WatchConnectivity               0x36156f28 __57-[WCSession onqueue_completeSwitchTask:withSessionState:]_block_invoke_2 + 380 (WCSession.m:1509)
8   Foundation                      0x22f1eb4c __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 16 (NSOperation.m:1541)
9   Foundation                      0x22e2ca00 -[NSBlockOperation main] + 84 (NSOperation.m:1560)
10  Foundation                      0x22f20d80 __NSOPERATION_IS_INVOKING_MAIN__ + 20 (NSOperation.m:2184)
11  Foundation                      0x22e2c6ec -[NSOperation start] + 752 (NSOperation.m:2201)
12  Foundation                      0x22f21750 __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 20 (NSOperation.m:2215)
13  Foundation                      0x22f21230 __NSOQSchedule_f + 180 (NSOperation.m:2226)
14  libdispatch.dylib               0x21e43c1c _dispatch_call_block_and_release + 24 (init.c:1408)
15  libdispatch.dylib               0x21e44fc0 _dispatch_client_callout + 16 (object.m:495)
16  libdispatch.dylib               0x21e47700 _dispatch_continuation_pop + 496 (inline_internal.h:2484)
17  libdispatch.dylib               0x21e46e18 _dispatch_async_redirect_invoke + 588 (queue.c:803)
18  libdispatch.dylib               0x21e53cfc _dispatch_root_queue_drain + 356 (inline_internal.h:2525)
19  libdispatch.dylib               0x21e54494 _dispatch_worker_thread2 + 116 (queue.c:6628)
20  libsystem_pthread.dylib         0x2207b6c8 _pthread_wqthread + 216 (pthread.c:2364)
21  libsystem_pthread.dylib         0x22081808 start_wqthread + 8

Thread 6:
0   libsystem_pthread.dylib         0x22081800 start_wqthread + 0

Thread 7:
0   libsystem_pthread.dylib         0x22081800 start_wqthread + 0

Thread 5 crashed with ARM Thread State (64-bit):
    x0: 0x0000000014ee1b10   x1: 0x0000000048c0cc97   x2: 0x0000000000005002   x3: 0x0000000000000000
    x4: 0x0000000014ee1af0   x5: 0x0000000000000002   x6: 0x0000000000000000   x7: 0x0000000000000000
    x8: 0x000000004fb0e000   x9: 0x0000000022533950  x10: 0x00000000153c2e00  x11: 0x000000000000003f
   x12: 0x00000000153c2eb8  x13: 0x00000000001c0369  x14: 0x0000000000000000  x15: 0x000000005cd5d1ff
   x16: 0x0000000050b251d8  x17: 0x000000002235c024  x18: 0x0000000000000000  x19: 0x0000000014ee1b10
   x20: 0x0000000004600790  x21: 0x0000000014ee1b10  x22: 0x0000000000005002  x23: 0x0000000014d8e900
   x24: 0x0000000000000001  x25: 0x0000000004a65000  x26: 0x000000000000c000  x27: 0x0000000004a65d60
   x28: 0x00000000c0004002   fp: 0x00000000192ee8b0   lr: 0x00000000223efda4
    sp: 0x00000000192ee840   pc: 0x00000000224c58b0 cpsr: 0x60000000
   esr: 0xf2000001  Address size fault

WatchConnectivityManager class:

class WatchConnectivityManager {

    static let shared = WatchConnectivityManager()

    let session = WCSession.default

    func sendWatchInfo() {

            if session.activationState == .activated {

                let name = getCurrentWatchInfo()

                let message: [String : Any] = ["appleWatchName" : name]

                if session.isReachable {
                    session.sendMessage(message,
                                        replyHandler: nil,
                                        errorHandler: nil)
                }

                do {
                    try session.updateApplicationContext(message)
                } catch(let error) {
                    fatalError(error.localizedDescription)
                }
            }
        }

        private func getCurrentWatchInfo() -> String {

            let name: String

            name = WKInterfaceDevice.current().name

            return name
    }
}
1 Answers

Even though the API says that WKInterfaceDevice.current().name is a String instead of String?, name is somehow actually a nil value in some cases.

It can't be nil. name is a property declared as:

var name: String { get }

It can be an empty string, but not nil (Swift context). And the Objective-C:

@property(nonatomic, readonly, copy) NSString *name;

It's encapsulated with the NS_ASSUME_NONNULL_BEGIN & NS_ASSUME_NONNULL_END which effectively means:

@property(nonatomic, readonly, copy) NSString * _Nonnull safeName;

Read Nullability and Objective-C to see how it affects Objective-C -> Swift.

Actually it can be nil in the Objective-C context, but it violates the _Nonnull contract then.

As a possible solution, I'm thinking that instead of name: String I should use name: String?.

I don't think it's going to help even if you can do this. Imagine you have the following method1:

- (NSString * _Nonnull)canNotBeNilNothing {
    return nil;
}

Used in Swift:

let name: String? = WKInterfaceDevice.current().canNotBeNilNothing();
print("\(String(describing: name))")

You still get the Optional(""), not nil. And it's expected, because there's this _Nonnull (it violates the contract, but it's another story).

You can create something like this if you are really sure it can return nil in Objective-C:

- (NSString * _Nullable)maybeName {
    return [self name];
}

And then you can use String? in Swift and it can become nil if [self name] will return nil.

Possible causes of your problem

  • Bug somewhere in the WatchKit (Incorrect nullability annotation, ...)
  • Something else

I'm not sure what's happening, because I didn't see the stacktrace.

Possible solution

WatchKit & Objective-C problem (throws an exception)? It might be fixable with the following wrapper in Objective-C:

- (NSString * _Nullable)maybeName {
    @try {
        return [self name];
    }
    @catch (NSException *exception) {
        // Return nil or handle it your way
        return nil;
    }
}

Bridging issue (incorrect nullability)? It might be fixable with the following code in Swift:

extension WKInterfaceDevice {
    var maybeName: String? {
        self.perform(#selector(getter: WKInterfaceDevice.name))?.takeRetainedValue() as! String?
    }
}

1 In general, you should look at nullable and nonnull roughly the way you currently use assertions or exceptions: violating the contract is a programmer error. In particular, return values are something you control, so you should never return nil for a non-nullable return type unless it is for backwards-compatibility. (Nullability and Objective-C)

Related