Swift:Downcast导致应用程序崩溃,为什么?

时间:2015-02-10 20:07:34

标签: ios cordova swift

我有以下代码片段,我在某些设备上崩溃了:

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>返回true,为什么contactImagesByEmails as Array<String>会失败?

请帮忙,

[编辑]

command的类型为CDVInvokedUrlCommand

@interface CDVInvokedUrlCommand : NSObject {
    NSString* _callbackId;
    NSString* _className;
    NSString* _methodName;
    NSArray* _arguments;
}

3 个答案:

答案 0 :(得分:2)

我不知道这是否能真正解决问题,但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> {
    ...
}

答案 1 :(得分:1)

也许尝试另一种获取转换值的方法:

if let contactImagesByEmails = obj["emails"] as? [String] {
       results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(contactImagesByEmails) as Dictionary<String,AnyObject>
    }

我也想知道你的崩溃是不是在原始代码中命名你的变量“array”......

答案 2 :(得分:1)

逐步简化此操作,减少对AnyObject的引用(当然不是AnyObject!)。编译器可能会放弃一些非法的东西,因为当你开始拔出AnyObject时,你会说“我确切地知道我在做什么;不要检查这个。”

您希望此代码类似于:

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填充异构类型。你在那里创建一个类来保存它们而不是枚举。)