我在Apple Watch应用中突然出现unconditionallyBridgeFromObjectiveC
崩溃。我无法在本地复制它,也从未通过常规使用在测试设备上遇到它。这是有关异常的信息:
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]
崩溃报告显示它正在此代码的第二行:
let name: String
name = WKInterfaceDevice.current().name
(为了方便阅读,我将它们放在单独的行中)
我不是很熟悉Objective-C,或者与Objective-C价值观有关的事情可能失败,但是根据我在互联网上发现的情况,这是我的猜测:
即使the API says WKInterfaceDevice.current().name
是String
而不是String?
,name
在某些情况下实际上还是一个nil
值。
作为一种可能的解决方案,我认为应该使用name: String
而不是name: String?
,然后确保它以后不为零。这有意义吗?这将有助于解决该问题,还是可能会因为尝试以WKInterfaceDevice.current().name
类型的常量存储String?
而仍然崩溃?我首先应该对WKInterfaceDevice.current().name
做其他安全检查吗?
此崩溃发生的次数不多(在大约5天内,至少有7台设备在大约5000台设备中,大约5天之内),但这是我最新版本的应用程序中最频繁发生的崩溃,因此,我尝试将其作为学习的机会,使我的应用程序更强大。我想也许这可能是WatchKit中的问题,而不是我的代码有问题?还是只能使用Objective-C检查和解决的问题?
尽管API表示WKInterfaceDevice.current().name
是String
而不是String?
,但在某些情况下name
实际上是nil
值。
不能为nil
。 name
是声明为:
var name: String { get }
它可以是一个空字符串,但不能是nil
(Swift上下文)。和Objective-C:
@property(nonatomic, readonly, copy) NSString *name;
[NS_ASSUME_NONNULL_BEGIN
和NS_ASSUME_NONNULL_END
封装,实际上表示:
@property(nonatomic, readonly, copy) NSString * _Nonnull safeName;
阅读Nullability and Objective-C以了解它如何影响Objective-C-> Swift。
实际上,在Objective-C上下文中可以是nil
,但那时它违反了_Nonnull
合同。
作为一种可能的解决方案,我认为我应该使用name: String
而不是name: String?
。
即使您可以做到,我认为也不会有所帮助。假设您有以下方法1:
- (NSString * _Nonnull)canNotBeNilNothing {
return nil;
}
在Swift中使用:
let name: String? = WKInterfaceDevice.current().canNotBeNilNothing();
print("\(String(describing: name))")
您仍然得到Optional("")
,而不是nil
。可以预见,因为有这个_Nonnull
(它违反了合同,但这是另外一回事了。)>
如果确实确定它可以在Objective-C中返回nil
,则可以创建这样的内容:
- (NSString * _Nullable)maybeName { return [self name]; }
然后您可以在Swift中使用
String?
,如果nil
将返回[self name]
,则它可以变为nil
。>您的问题的可能原因
我不确定发生了什么,因为我没有看到堆栈跟踪。
可能的解决方案
WatchKit和Objective-C问题(引发异常)?它可以用Objective-C中的以下包装器修复:
- (NSString * _Nullable)maybeName { @try { return [self name]; } @catch (NSException *exception) { // Return nil or handle it your way return nil; } }
桥接问题(不正确的为空性?它可能可以通过Swift中的以下代码修复:
通常,您应该大致查看extension WKInterfaceDevice { var maybeName: String? { self.perform(#selector(getter: WKInterfaceDevice.name))?.takeRetainedValue() as! String? } }
1
nullable
和nonnull
当前使用断言或异常的方式:违反合同是程序员错误。特别是,返回值是由您控制的东西,因此,除非返回值是向后兼容的,否则切勿为非空返回类型返回nil
。 (Nullability and Objective-C)