Swift 3 NSDictionary到Dictionary转换会导致NSInvalidArgumentException

时间:2016-09-20 13:54:01

标签: objective-c json swift3 nsdictionary

我刚刚将我的项目从Swift 2.2转换为3.0 ,我的测试中出现了一个新的异常。我在我的一个测试中有一些Objective C代码,它从文件中读取一些JSON:

+ (NSDictionary *)getJSONDictionaryFromFile:(NSString *)filename {
    /* some code which checks the parameter and gets a string of JSON from a file.
     * I've checked in the debugger, and jsonString is properly populated. */

    NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
    return jsonDict;
}

我从一些Swift代码中调用它:

let expectedResponseJSON = BZTestCase.getJSONDictionary(fromFile: responseFileName)

这个大多数当时很好用,但我有一个JSON文件会导致错误:

failed: caught "NSInvalidArgumentException", "-[__NSSingleObjectArrayI enumerateKeysAndObjectsUsingBlock:]: unrecognized selector sent to instance 0x608000201fa0"

关于这一点的奇怪之处在于,在getJSONDictionaryFromFile方法返回之后以及在填充Swift代码中expectedResponseJSON之前生成错误。对我来说,这似乎是说从NSDictionaryDictionary的转换是问题所在。违规的JSON文件就是这个:

[
  {
    "status": "403",
    "title": "Authentication Failed",
    "userData": {},
    "ipRangeError": {
      "libraryName": "Name goes here",
     "libraryId": 657,
      "requestIp": "127.0.0.1"
    }
  }
]

如果我删除最外面的[],则此错误消失。我不能成为唯一一个使用数组作为Swift 3中JSON文件的顶级实体的人,我做错了什么?我该怎么做才能解决这个错误?

1 个答案:

答案 0 :(得分:4)

正如评论中所引用的那样,问题是getJSONDictionaryFromFile返回NSDictionary *而我的JSON输入是一个数组。唯一的谜团是为什么它曾经在Swift 2.2中运行!我最终将expectedResponseJSON更改为Any?,并在Swift中重写了我的Objective C代码:

class func getStringFrom(file fileName: String, fileExtension: String) -> String {
    let filepath = Bundle(for: BZTestCase.self).path(forResource: fileName, ofType: fileExtension)
    return try! NSString(contentsOfFile: filepath!, usedEncoding: nil) as String
}

class func getJSONFrom(file fileName: String) -> Any? {
    let json = try! JSONSerialization.jsonObject(with: (getStringFrom(file: fileName, fileExtension: ".json").data(using: .utf8))!, options:.allowFragments)
    return json
}

作为对可能剪切和粘贴此代码的任何人的说明,我使用try!filepath!代替try?if let...,因为此代码仅用于测试,如果我的输入不是我期望的那样,我希望它尽快崩溃。