Reputation: 2899
I have just converted my project from Swift 2.2 to 3.0, and I'm getting a new exception thrown in my tests. I have some Objective C code in one of my tests which reads in some JSON from a file:
+ (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;
}
I'm calling this from some Swift code:
let expectedResponseJSON = BZTestCase.getJSONDictionary(fromFile: responseFileName)
This works just fine most of the time, but I have one JSON
file which causes the error:
failed: caught "NSInvalidArgumentException", "-[__NSSingleObjectArrayI enumerateKeysAndObjectsUsingBlock:]: unrecognized selector sent to instance 0x608000201fa0"
The strange thing about this is that the error is generated after the getJSONDictionaryFromFile
method returns and before expectedResponseJSON
in the Swift code is populated. To me, this seems to say that it's the conversion from an NSDictionary
to Dictionary
which is the problem. The offending JSON file is this one:
[
{
"status": "403",
"title": "Authentication Failed",
"userData": {},
"ipRangeError": {
"libraryName": "Name goes here",
"libraryId": 657,
"requestIp": "127.0.0.1"
}
}
]
If I remove the outermost enclosing []
, this error goes away. I can't be the only person using an array as the top level entity of a JSON file in Swift 3, am I doing something wrong? What can I do to get around this error?
Upvotes: 1
Views: 922
Reputation: 2899
As is referenced in the comments, the problem is that getJSONDictionaryFromFile
returns an NSDictionary *
and my JSON input is an array. The only mystery is why this used to work in Swift 2.2! I ended up changing expectedResponseJSON
to be an Any?
, and rewrote my Objective C code in Swift:
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
}
As a note to anyone who might cut and paste this code, I used try!
and filepath!
instead of try?
and if let...
because this code is used exclusively in tests, so I want it to crash as soon as possible if my inputs are not what I expect them to be.
Upvotes: 4