Search code examples
iosswiftiphonensmutablearraynsarray

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


Below line of code is producing the error,

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

As the error says I understand its a cast exception, but I'm not able to modify the code to make it work. I'm kinda new to Swift, so any help would be appreciated. Below is my JSON.object

So, I checked and this is my JSON.object

[["offset": 30119146, "file_size": 30119146, "filename": video_220120201129271580.mp4, "mediaPath": file:///Users/evuser/Library/Developer/CoreSimulator/Devices/B9B0232F-237D-4413-BB81-BD5FAC727305/data/Containers/Data/Application/401D5D91-4500-434A-98FE-BD416135A1C7/Documents/video_220120201129271580.mp4, "status": completed, "group_id": fKQ2Xd9bE0cXchsw, "createdDate": 2020/01/22 13:59:47, "_id": 5e27e4d3138c8801cd3c26ca, "user_id": 21, "mime_type": video/mp4, "dest_path": /video_220120201129271580.mp4, "resource_id": 3a743d84-eafe-41e5-9f4c-dece67598c32], 
["offset": 6435018, "file_size": 6435018, "filename": video_220120201127525480.mp4, "mediaPath": file:///Users/evuser/Library/Developer/CoreSimulator/Devices/B9B0232F-237D-4413-BB81-BD5FAC727305/data/Containers/Data/Application/401D5D91-4500-434A-98FE-BD416135A1C7/Documents/video_220120201127525480.mp4, "status": completed, "group_id": ffoHuGL0Z17vOqY9, "createdDate": 2020/01/22 13:58:10, "_id": 5e27e472138c8801cd3c26c9, "user_id": 21, "mime_type": video/mp4, "dest_path": /video_220120201127525480.mp4, "resource_id": 50e34fd5-b488-4861-aedd-03ea1ed0d91c]]

Solution

  • 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.