macOS 输入法的公用 API 参数可能会被系统喂 nil。一个最常见的情形:
- 点输入法选单「显示表情符号和其他符号」:
- 确保已经切换到要测试的输入法,然后在这个符号输入窗口当中使用鼠标点击输入任意符号。
- 你会亲眼看到输入法崩溃重启了,且生成了 console 错误报告:
-------------------------------------
Translated Report (Full Report Below)
-------------------------------------
Process: 输入法名称 [34680]
Path: /Library/Input Methods/输入法名称.app/Contents/MacOS/输入法名称
Identifier: com.作者名称.inputmethod.输入法名称
Version: v114.514.1919810 (20230506052004)
Code Type: X86-64 (Native)
Parent Process: launchd [1]
User ID: 502
Date/Time: 2023-05-29 20:06:41.3789 +0800
OS Version: macOS 13.4 (22F66)
Report Version: 12
Bridge OS Version: 7.5 (20P5058)
Anonymous UUID: 08378DA6-1F38-296F-EE86-338AA00FC385
Sleep/Wake UUID: 1F6DE16D-2E2F-4637-8E75-E0F39DD20DE8
Time Awake Since Boot: 85000 seconds
Time Since Wake: 3258 seconds
System Integrity Protection: enabled
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes: 0x0000000000000001, 0x0000000000000000
Termination Reason: Namespace SIGNAL, Code 4 Illegal instruction: 4
Terminating Process: exc handler [34680]
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 Fire 0x10e504c02 0x10e4f8000 + 52226
1 Fire 0x10e505261 0x10e4f8000 + 53857
2 InputMethodKit 0x7ff92b37170c -[IMKServer handleEvent_Common:characterIndex:edge:clientWrapper:controller:] + 697
3 InputMethodKit 0x7ff92b36686e __63-[IMKServer handleEvent:characterIndex:edge:asyncClient:reply:]_block_invoke_2 + 676
4 ViewBridge 0x7ff822b83a4a +[NSServiceViewController withHostAppAuditToken:invoke:] + 92
5 InputMethodKit 0x7ff92b3665be __63-[IMKServer handleEvent:characterIndex:edge:asyncClient:reply:]_block_invoke + 201
6 InputMethodKit 0x7ff92b373146 __IMKXPCPerformBlockOnMainThread_block_invoke + 25
7 CoreFoundation 0x7ff81adbdb71 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
8 CoreFoundation 0x7ff81adbdaaa __CFRunLoopDoBlocks + 398
9 CoreFoundation 0x7ff81adbcd7a __CFRunLoopRun + 2015
10 CoreFoundation 0x7ff81adbbf31 CFRunLoopRunSpecific + 560
11 HIToolbox 0x7ff824837dad RunCurrentEventLoopInMode + 292
12 HIToolbox 0x7ff824837bbe ReceiveNextEventCommon + 657
13 HIToolbox 0x7ff824837918 _BlockUntilNextEventMatchingListInModeWithFilter + 64
14 AppKit 0x7ff81de505d0 _DPSNextEvent + 858
15 AppKit 0x7ff81de4f47a -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1214
16 AppKit 0x7ff81de41ae8 -[NSApplication run] + 586
17 AppKit 0x7ff81de15d02 NSApplicationMain + 817
18 Fire 0x10e4fb609 0x10e4f8000 + 13833
19 dyld 0x7ff81a98841f start + 1903
如果你胆子够肥,敢用 Xcode 给输入法玩实时侦错的话,你会发现 IMKInputController.handle() 当中首次读取 event 参数时的位置、就是输入法崩溃的那一刻。
对这种情形的解决方式就是在这个函式最开头插入这句即可:
guard let event = event else { return }
如果您的输入法是用 ObjC++ 写的,您得同时检测 nullPtr 与 NSNull:
- (BOOL)handleEvent:(NSEvent *)event client:(id)sender {
if (event == nullptr || [event isEqual:[NSNull null]]) {
return NO;
}
...
如果您的输入法是用 ObjC 写的,您得同时检测 nil 与 NSNull:
- (BOOL)handleEvent:(NSEvent *)event client:(id)sender {
if (event == nil || [event isEqual:[NSNull null]]) {
return NO;
}
...
类似情形可按照这个逻辑来处理。以上。
$ EOF.