0

I am trying to get string value in a json but I keep getting nil.

This is json structure

{
    "user": {
        "password": "...",
        "name": "...",
        "authToken": "...",
        "events": [
            {
                "uuid": (int)
            }
        ]
    }
}

this is how I am decoding.

do {
       let json = try JSONSerialization.jsonObject(with: responseData, options:[]) as! [String : Any?]

       let authToken: String = json["authToken"] as! String

       print(authToken)

   } catch let error {
       print(error)
   }

but I keep getting nil value in my console

4
  • try json["user"]["authToken"] Commented Mar 4, 2020 at 15:16
  • @toto this is not swiftyJSON so that would not work Commented Mar 4, 2020 at 15:18
  • Use Codable and JSONDecoder. Do not use the legacy JSONSerialization and force casting. In any case, you need to decode several levels, you cannot just access authToken, which is nested inside the user Dictionary of the JSON. Commented Mar 4, 2020 at 15:19
  • As pointed by others, your top-level key on your json object is "user". Commented Mar 4, 2020 at 15:26

3 Answers 3

1

You need

let user = json["user"] as! [String:Any] 
let authToken = user["authToken"] as! String
Sign up to request clarification or add additional context in comments.

Comments

0

You can access authToken using chaining transformations like this:

let json = try JSONSerialization.jsonObject(with: responseData, options:[]) as? [String : Any]

let authToken = json
    .flatMap { $0["user"] as? [String: Any] }
    .flatMap { $0["authToken"] as? String }

In the end, you will have an optional authToken property. If JSON is valid and authToken exists, you can unwrap it and reach the value!

3 Comments

Don't use flatMap with Optional values, that's deprecated already. Moreover, using flatMap or compactMap to get the value of a single key from a Dictionary is a really bad idea - and your current implementation won't even work, since that flatMap would iterate over all key-value pairs of the Dictionary.
Hello! Function .flatMap is deprecated on Array (now you should use .compactMap), but not Optional type. Using Codable protocol is a better idea, I know. But in this case - just for testing, why we can't use provided answer?
I think you've missed, that in my case, .flatMap acts on Optional type, but not on Dictionary. It will not iterate through the collection, it will just perform the transformation, in case the value is not nil.
0

Create this Object model:

import Foundation

// MARK: - Matrix
struct Matrix: Codable {
    let user: User
}

// MARK: - User
struct User: Codable {
    let password, name, authToken: String
    let events: [Event]
}

// MARK: - Event
struct Event: Codable {
   let uuid: Int
}

Use it like this:

do {
    let matrix = try JSONDecoder().decode(Matrix.self, from: jsonData)
    let token = matrix.user.authToken
} catch let error {
    print(error.localizedDescription)
}

replace Matrix with your desire object name

2 Comments

Don't use try? to mask errors. Use try inside a do-catch block.
updated my answer, though is obvious that it should use the safest way

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.