Swift JSON Error:Could Not Cast Value of Type '_Nsdictionarym' to 'Nsarray'

Could not cast value of type '__NSDictionaryI' to 'NSArray'

The error is pretty clear: json is a dictionary ([String:Any]), not an array. Don't use NSArray – as well as horrible as AnyObject).value(forKey: – in Swift at all!

And always conditional bind the value to avoid crashes

...
if let json = response.result.value as? [String:Any], // <- Swift Dictionary
let results = json["results"] as? [[String:Any]] { // <- Swift Array

for result in results {
print(result["name"] as! String)
}

There is no key imageURL in the JSON at all

Could not cast value of type '__NSDictionaryM' to 'NSArray

The error message says

Could not cast the actual type NSDictionary to the expected type NSArray

[NSDictionary] means an array of dictionaries, but the value of response is clearly a dictionary, represented by a pair of braces.

So it's actually

let quoteDictionary = quotesData["response"] as! NSDictionary

But it's recommended to use Swift native collection types

let quoteDictionary = quotesData["response"] as! Dictionary<String,AnyObject>

Could not cast value of type '__NSDictionaryI'

.responseJSON returns deserialized JSON, in this case a Dictionary. It cannot be cast to Data what the error clearly confirms.

To get the raw data you have to specify .responseData

Replace

.responseJSON {
response in
switch (response.result) {
case .success:
do {
let users = try JSONDecoder().decode(OrderStore.self, from: response.result.value! as! Data)

with

.responseData {
response in
switch response.result {
case .success(let data):
do {
let users = try JSONDecoder().decode(OrderStore.self, from: data)

Consider that AF 5 supports even .responseDecodable to decode directly into the model

.responseDecodable {
(response : DataResponse<OrderStore,AFError>) in
switch response.result {
case .success(let users): print(users)

Side notes:

  • As mentioned in your previous question there is no AnyObject in the AF API. The parameters are [String:Any] and responseData is the decoded type. I recommend to make the function generic and use the convenient Result type.

  • Delete the break statements. This is Swift.

Could not cast value of type 'Swift.__SwiftDeferredNSArray' (0x104cd8ae8) to 'NSMutableArray' (0x7fff87c52960)

It seems that JSON.object may not be an array. Or at least not mutable array. It will be hard for us to identify your issue without having a look into JSON.object. A quick fix may actually be

let response1 : NSMutableArray = NSMutableArray.init(array: (JSON.object as! NSArray).value(forKey: "media_list") as! NSArray)

but I would try to dig in a bit more. Try to check what exactly is going on and try to avoid old Objective-C Next Step (NS) objects. Do it step by step:

let response1: [Any]? = {
guard let mainArray = JSON.object as? [Any] else {
print("Outer object is not an array. Check type of \(JSON.object)")
return nil
}
var mutableVersionOfArray = mainArray // This already creates a mutable copy because we used "var" instead of "let"
guard let mediaList = mutableVersionOfArray.value(forKey: "media_list") as? [Any] else {
print("Inner object is not an array. Check type of \(mutableVersionOfArray.value(forKey: "media_list"))")
return nil
}
return mediaList
}()

But this code makes no sense to me. Looking at your code I expect that your JSON object looks similar to:

{
"media_list": [{}, {}]
}

in this case you are looking at dictionaries. Try the following:

let mediaList: [Any]? = {
guard let topDictionary = JSON.object as? [String: Any] else {
print("Outer object is not a dictionary. Check type of \(JSON.object)")
return nil
}
guard let mediaListItem = topDictionary["media_list"] else {
print("There is no media_list in payload")
return nil
}
guard let mediaList = mediaListItem as? [Any] else {
print("mediaList is not an array")
return nil
}
return mediaList
}

I hope you can see the difference between an array and a dictionary. Array has some N ordered elements in it while a dictionary has key-value pairs. So to access a value under key you call it as dictionary[key]. Your whole code if you are correct could simply be:

let response1 = (JSON.object as? [String: Any])?["media_list"] as? [Any]

but if it returns nil it may be a bit hard to debug what went wrong.

Swift JSON error : Could not cast value of type '__NSDictionaryM' to 'NSArray'

The bitnami response starts with a { and it is therefore a JSON object, which corresponds to an NSDictionary. The other one starts with [ which indicates an array.

You need to change the type of json to Dictionary<String, AnyObject>, and deserialize as follows:

json = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! Dictionary<String, AnyObject>

Could not cast value of type '__NSArrayI' (0x10df73c08) to 'NSDictionary' (0x10df74108)

Your response is of Array of Dictionary not Dictionary, so if you want all the dictionary you can access it using loop.

if let array = response.result.value as? [[String: Any]] {
//If you want array of task id you can try like
let taskArray = array.flatMap { $0["task_id"] as? String }
print(taskArray)
}

Could not cast value of type '__NSDictionaryI' to 'NSMutableDictionary'

This is no surprise because it's exactly the same behavior as in Objective-C.

In ObjC you cannot cast an immutable type to a mutable. Running this code

NSDictionary *dict = @{@"Foo":@"1"};
NSMutableDictionary *mutableDict = (NSMutableDictionary *)dict;
[mutableDict setObject:@"2" forKey: @"Bar"];

raises an exception

-[__NSSingleEntryDictionaryI setObject:forKey:]: unrecognized selector sent to instance

because the type remains immutable. You have to create a new NSMutableDictionary instance

NSMutableDictionary *mutableDict = [NSMutableDictionary dictionaryWithDictionary:dict];

Ironically – I'm still talking about ObjC – in case of NSJSONSerialization the famous option .mutableContainers comes in. With this option you can create a mutable array / dictionary directly, please note, only in Objective-C.

On the other hand in Swift this option makes no sense anyway because Swift Dictionary / Array and the NSMutable... counterparts are not related to each other, and in Swift you can make a (native) type mutable simply with the var keyword.

So write

var json = try JSONSerialization.jsonObject(with: responseData) as! [String:Any]

The bottom line is:

Don't use NSMutable... collection types in Swift at all.



Related Topics



Leave a reply



Submit