0

I'm trying to loop through an embedded JSON array and extract all the values to put in a local array. This is what the JSON looks like:

"welcome": {
  "data": {
    "tncUrl": ""
  },
  "items": [
    {
      "newUser": [
        {
          "stepConcept": false
        },
        {
          "stepSafety": true
        },
        {
          "stepFacilitator": true
        },
        {
          "stepTransparency": true
        }
      ],
      "switcher": [
        {
          "stepConcept": true
        },
        {
          "stepSafety": true
        },
        {
          "stepFacilitator": true
        },
        {
          "stepTransparency": true
        }
      ]
    }
  ]
}

I'm able to get to a point where I can see I'm retrieving values for "newUser", the problem is looping through those values and adding them to an array. I'm getting a EXC_BAD_INSTRUCTION error when doing so. This is the code I'm using to get those values:

  func prepareArrayOfViews(userType: User)
    {
        if (welcomeJSON != nil)
        {
            let items : NSArray? = welcomeJSON!.value(forKey: "items") as? NSArray

            if (items == nil)
            {
                listOfViews = ["stepConcept", "stepSafety", "stepFacilitator", "stepTransparency"]
                maxPages = listOfViews.count
                return
            }

            if (items != nil) {

                if let newUser = (items?.value(forKey: "newUser") as? NSArray){

                    //Below is where the error "EXC_BAD_INSTRUCTION"
                    for key in (newUser as! NSDictionary).allKeys
                    {
                        if (((newUser as! NSDictionary).value(forKey: key as! String) as? Bool)!)
                        {
                            listOfViews.append(key as! String)
                        }
                    }

                }

                if (listOfViews.count == 0)
                {
                    listOfViews = ["stepConcept", "stepSafety", "stepFacilitator", "stepTransparency"]
                }

                maxPages = listOfViews.count
            }
        }
    }
2
  • 1
    Are you responsible for sending the JSON? If yes why do you send multiple dictionaries with only one key in an array (rather than one dictionary)? Commented Jul 29, 2017 at 17:21
  • The code was already in place, I'm rewriting it to fit the new json data Commented Jul 29, 2017 at 17:27

2 Answers 2

2

I have changed your code to use native Swift structs. Since you are not handling errors or doing anything when your optional unwrapping doesn't work, I have also changed the unwrapping to guard statements.

Other than the serious problems with Swift coding practices, your issue was that you were trying to iterate through an array of dictionaries as a simple dictionary.

func prepareArrayOfViews(userType: User){
    guard let welcomeJSON = welcomeJSON else {return}
    guard let items = welcomeJSON["items"] as? [[String:Any]] else {
        listOfViews = ["stepConcept", "stepSafety", "stepFacilitator", "stepTransparency"]
            maxPages = listOfViews.count
            return
    }
    for item in items {
        if let newUser = item["newUser"] as? [[String:Any]] {
            for embeddedDict in newUser {
                for (key, value) in embeddedDict { 
                    if let val = value as? Bool, val == true {
                        listOfViews.append(key)
                    }
                }
            }
        } else if let switcher = item["switcher"] as? [[String:Any]]{
            for embeddedDict in switcher {
                for (key, value) in embeddedDict { 
                    if let val = value as? Bool, val == true {
                        //do whatever you need to with the value
                    }
                }
            }
        }
    }
    if (listOfViews.count == 0){
         listOfViews = ["stepConcept", "stepSafety", "stepFacilitator", "stepTransparency"]
    }   
    maxPages = listOfViews.count
}
Sign up to request clarification or add additional context in comments.

9 Comments

Thanks for your help but the code is giving an error on the line : for (key, value) in embeddedDict - Type '(key: String, value: Any)' does not conform to protocol 'Sequence'
@SwiftyJD my bad, accidentally casted newUser to a Dictionary instead of an array of dictionaries. See my updated code, it should work now.
Glad I could help. If you found my answer helpful, please accept it.
After further testing it looks like something might be wrong with the line: guard let items = welcomeJSON["items"] as? [String:Any] because Its goes right to the else statement even when the JSON is available
Ok, I'll let the API guys know, thanks for your help, saved my Saturday afternoon.
|
1

Because

//here newUser is an NSArray

     if let newUser = (items?.value(forKey: "newUser") as? NSArray){

                        //here newUser forced to NSDictionary 
                        for key in (newUser as! NSDictionary).allKeys

try to change this part to

if let newUsers = (items?.value(forKey: "newUser") as? NSArray){

                for newUser in newUsers
                {
                    for key in (newUser as! NSDictionary).allKeys
                {
                    if (((newUser as! NSDictionary).value(forKey: key as! String) as? Bool)!)
                    {
                        listOfViews.append(key as! String)
                    }
                }
                }

            }

3 Comments

I see, I do need to get the items in the newUser array as a dictionary for the key valued pairs, am I missing something? -Nevermind I see you updated your answer.
I get a SIGABRT error on this line: for key in (newUser as! NSDictionary).allKeys
@SwiftyJD see my answer, which uses native Swift structs and no unsafe unwrappings

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.