Swift: Downcast导致应用程序崩溃,为什么?
Swift: Downcast causes application to crash, why?
我有以下代码片段在某些设备上崩溃:
Crashed: com.apple.root.default-qos
EXC_BAD_ACCESS KERN_INVALID_ADDRESS at 0x00000000cbd
代码:
var obj:AnyObject = command.arguments[0] as AnyObject!
var theData:AnyObject = obj["getContactImagesByEmails"] as AnyObject!
if let contactImagesByEmails:AnyObject = obj["emails"]{
if contactImagesByEmails is Array<String>{
/*line 176*/ let array:Array<String> =
contactImagesByEmails as Array<String> // CRASH happens here
results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(array) as Dictionary<String,AnyObject>
}
}
完整堆栈跟踪
Thread : Crashed: com.apple.root.default-qos
0 libswiftCore.dylib 0x0000000100559794 swift_unknownRetain + 32
1 MyApp 0x000000010017c8a0 MyApp.Plugin.(getContactImagesByEmails (MyApp.Plugin) -> (ObjectiveC.CDVInvokedUrlCommand) -> ()).(closure #1) (Plugin.swift:176)
2 MyApp 0x000000010017c8a0 MyApp.Plugin.(getContactImagesByEmails (MyApp.Plugin) -> (ObjectiveC.CDVInvokedUrlCommand) -> ()).(closure #1) (Plugin.swift:176)
3 MyApp 0x00000001001790b0 partial apply forwarder for reabstraction thunk helper from @callee_owned () -> (@unowned ()) to @callee_owned (@in ()) -> (@out ()) with unmangled suffix "125" (Plugin.swift:62)
4 MyApp 0x0000000100179120 partial apply forwarder for reabstraction thunk helper from @callee_owned (@in ()) -> (@out ()) to @callee_owned () -> (@unowned ()) with unmangled suffix "128" (Plugin.swift:62)
5 libdispatch.dylib 0x00000001937e13ac _dispatch_call_block_and_release + 24
6 libdispatch.dylib 0x00000001937e136c _dispatch_client_callout + 16
7 libdispatch.dylib 0x00000001937ed40c _dispatch_root_queue_drain + 1152
8 libdispatch.dylib 0x00000001937ee75c _dispatch_worker_thread3 + 108
9 libsystem_pthread.dylib 0x00000001939bd2e4 _pthread_wqthread + 816
Plugin.swift:176
指向:
let array:Array<String> = contactImagesByEmails as Array<String>
我错过了什么吗?我认为这段代码应该是安全的。
如果contactImagesByEmails is Array<String>
returnstrue
,为什么contactImagesByEmails as Array<String>
失败了?
请帮忙,
[编辑]
command
的类型为 CDVInvokedUrlCommand
@interface CDVInvokedUrlCommand : NSObject {
NSString* _callbackId;
NSString* _className;
NSString* _methodName;
NSArray* _arguments;
}
我不知道这是否真的可以解决问题,但在 2 if
和后面的 let
中有一点冗余。可以简单的写成:
if let contactImagesByEmails = obj["emails"] as? Array<String> {
results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(contactImagesByEmails) as Dictionary<String,AnyObject>
}
此外,在调用 getImagesByEmailAsWmContactImage
时结合可选绑定和可选向下转换会更安全
if let results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(contactImagesByEmails) as? Dictionary<String,AnyObject> {
...
}
最后,您确定 getInstance
是 属性 而不是方法吗?不应该是:
if let results = WmSqliteImagesModel.getInstance().getImagesByEmailAsWmContactImage(contactImagesByEmails) as? Dictionary<String,AnyObject> {
...
}
也许尝试另一种方法来获取转换值:
if let contactImagesByEmails = obj["emails"] as? [String] {
results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(contactImagesByEmails) as Dictionary<String,AnyObject>
}
我也想知道你的崩溃是否不是因为在你的原始代码中命名你的变量 "array"...
通过减少对 AnyObject
(当然不是 AnyObject!
)的引用来逐步简化此过程。编译器可能允许通过一些非法的东西,因为当你开始退出 AnyObject
时,你说的是 "I know exactly what I'm doing; don't check this."
您希望此代码类似于:
let obj = command.arguments[0]
if let contactImagesByEmails = obj["emails"] as? [String] {
results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(array) as? [String: AnyObject]
}
最后results
会是[String:AnyObject]?
这里的关键点是你应该尽可能多地删除对 AnyObject
的引用,并且你应该使用 if-let-as?
来确定类型是否符合你的期望。
事实上 command.arguments
充满了您必须进行类型检查的各种类型的东西,这是非常危险的,并且是严重设计问题的标志。如果那里真的有多种类型,你应该使用枚举而不是像 [String:AnyObject]
这样的随机事物进行类型检查。这就是枚举的明确用途。 (如果这是从 ObjC 桥接;枚举在这里可能是不可能的,但即使在 ObjC 中,正确的答案也很少是 NSArray
填充异构类型。你创建一个 class 来保存它们而不是枚举。)
我有以下代码片段在某些设备上崩溃:
Crashed: com.apple.root.default-qos
EXC_BAD_ACCESS KERN_INVALID_ADDRESS at 0x00000000cbd
代码:
var obj:AnyObject = command.arguments[0] as AnyObject!
var theData:AnyObject = obj["getContactImagesByEmails"] as AnyObject!
if let contactImagesByEmails:AnyObject = obj["emails"]{
if contactImagesByEmails is Array<String>{
/*line 176*/ let array:Array<String> =
contactImagesByEmails as Array<String> // CRASH happens here
results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(array) as Dictionary<String,AnyObject>
}
}
完整堆栈跟踪
Thread : Crashed: com.apple.root.default-qos
0 libswiftCore.dylib 0x0000000100559794 swift_unknownRetain + 32
1 MyApp 0x000000010017c8a0 MyApp.Plugin.(getContactImagesByEmails (MyApp.Plugin) -> (ObjectiveC.CDVInvokedUrlCommand) -> ()).(closure #1) (Plugin.swift:176)
2 MyApp 0x000000010017c8a0 MyApp.Plugin.(getContactImagesByEmails (MyApp.Plugin) -> (ObjectiveC.CDVInvokedUrlCommand) -> ()).(closure #1) (Plugin.swift:176)
3 MyApp 0x00000001001790b0 partial apply forwarder for reabstraction thunk helper from @callee_owned () -> (@unowned ()) to @callee_owned (@in ()) -> (@out ()) with unmangled suffix "125" (Plugin.swift:62)
4 MyApp 0x0000000100179120 partial apply forwarder for reabstraction thunk helper from @callee_owned (@in ()) -> (@out ()) to @callee_owned () -> (@unowned ()) with unmangled suffix "128" (Plugin.swift:62)
5 libdispatch.dylib 0x00000001937e13ac _dispatch_call_block_and_release + 24
6 libdispatch.dylib 0x00000001937e136c _dispatch_client_callout + 16
7 libdispatch.dylib 0x00000001937ed40c _dispatch_root_queue_drain + 1152
8 libdispatch.dylib 0x00000001937ee75c _dispatch_worker_thread3 + 108
9 libsystem_pthread.dylib 0x00000001939bd2e4 _pthread_wqthread + 816
Plugin.swift:176
指向:
let array:Array<String> = contactImagesByEmails as Array<String>
我错过了什么吗?我认为这段代码应该是安全的。
如果contactImagesByEmails is Array<String>
returnstrue
,为什么contactImagesByEmails as Array<String>
失败了?
请帮忙,
[编辑]
command
的类型为 CDVInvokedUrlCommand
@interface CDVInvokedUrlCommand : NSObject {
NSString* _callbackId;
NSString* _className;
NSString* _methodName;
NSArray* _arguments;
}
我不知道这是否真的可以解决问题,但在 2 if
和后面的 let
中有一点冗余。可以简单的写成:
if let contactImagesByEmails = obj["emails"] as? Array<String> {
results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(contactImagesByEmails) as Dictionary<String,AnyObject>
}
此外,在调用 getImagesByEmailAsWmContactImage
if let results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(contactImagesByEmails) as? Dictionary<String,AnyObject> {
...
}
最后,您确定 getInstance
是 属性 而不是方法吗?不应该是:
if let results = WmSqliteImagesModel.getInstance().getImagesByEmailAsWmContactImage(contactImagesByEmails) as? Dictionary<String,AnyObject> {
...
}
也许尝试另一种方法来获取转换值:
if let contactImagesByEmails = obj["emails"] as? [String] {
results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(contactImagesByEmails) as Dictionary<String,AnyObject>
}
我也想知道你的崩溃是否不是因为在你的原始代码中命名你的变量 "array"...
通过减少对 AnyObject
(当然不是 AnyObject!
)的引用来逐步简化此过程。编译器可能允许通过一些非法的东西,因为当你开始退出 AnyObject
时,你说的是 "I know exactly what I'm doing; don't check this."
您希望此代码类似于:
let obj = command.arguments[0]
if let contactImagesByEmails = obj["emails"] as? [String] {
results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(array) as? [String: AnyObject]
}
最后results
会是[String:AnyObject]?
这里的关键点是你应该尽可能多地删除对 AnyObject
的引用,并且你应该使用 if-let-as?
来确定类型是否符合你的期望。
事实上 command.arguments
充满了您必须进行类型检查的各种类型的东西,这是非常危险的,并且是严重设计问题的标志。如果那里真的有多种类型,你应该使用枚举而不是像 [String:AnyObject]
这样的随机事物进行类型检查。这就是枚举的明确用途。 (如果这是从 ObjC 桥接;枚举在这里可能是不可能的,但即使在 ObjC 中,正确的答案也很少是 NSArray
填充异构类型。你创建一个 class 来保存它们而不是枚举。)