5

As mentioned in the title of post,I'm getting NSInvalidArgumentException - 'Invalid top-level type in JSON write' when trying to convert Dictionary to JSON Data in swift

let userInfo: [String: String] = [
            "user_name" : username!,
            "password" : password!,
            "device_id" : DEVICE_ID!,
            "os_version" : OS_VERSION
        ]

let inputData = jsonEncode(object: userInfo)

. . .

static private func jsonEncode(object:Any?) -> Data?
    {
        do{
            if let encoded = try JSONSerialization.data(withJSONObject: object, options:[]) as Data?  <- here occured NSInvalidArgumentException

            if(encoded != nil)
            {
                return encoded
            }
            else
            {
                return nil
            }
        }
        catch
        {
            return nil
        }

    }

I'm passing Dictionary as parameter, not getting whats going wrong. Please help me guys.

Thanks!

iAkshay
  • 1,143
  • 1
  • 13
  • 35
  • Why did you add `as Data?` at the end of this line? – Eric Aya Dec 01 '16 at 13:04
  • Also, you pass `Any?` to `JSONSerialization.data(withJSONObject:)` but it should be safely unwrapped first. – Eric Aya Dec 01 '16 at 13:06
  • oh! 'as Data?' by mistake .. I'm new to swift. So please tell me what should be done.Thanx BTW for pointing out – iAkshay Dec 01 '16 at 13:09
  • 1
    Since you **do** want to encode something in the function it's pretty silly to declare the input parameter as optional. – vadian Dec 01 '16 at 13:17

1 Answers1

3

Note that you don't need all this stuff, your function could be as simple as:

func jsonEncode(object: Any) -> Data? {
    return try? JSONSerialization.data(withJSONObject: object, options:[])
}

If you really need to pass an Optional, then you have to unwrap it:

func jsonEncode(object: Any?) -> Data? {
    if let object = object {
        return try? JSONSerialization.data(withJSONObject: object, options:[])
    }
    return nil
}
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
  • Thanks Eric. This is working fine.Initially I'd code like `let encoded = try JSONSerialization.data(withJSONObject: object, options:[])` .. it gives me an error : **Error thrown from here are not handled** ... So I sarched for it and implemented accordingly, just confused with **?** and **!** mark, when and why to use it. – iAkshay Dec 01 '16 at 13:36
  • @AkshayGajarlawar When using `try?` as in my example you *don't need* a `do catch` block. `try?` is like `try` but returns an Optional instead of throwing errors we would have to catch. Using `!` as in your `"user_name" : username!` is different, it means that you are "force unwrapping" the Optional value. The common way to avoid forcing (which crashes if the value is nil) is to use `if let`. – Eric Aya Dec 01 '16 at 13:38
  • so your jsonEncode function would return nil if error thrown ? – iAkshay Dec 01 '16 at 13:42
  • 1
    Yes, it would ignore the error and just return nil. Returning `Data?` means that you're either returning `Data` or returning `nil`, depending on the success of the operation. If the call fails, `try?` gives nil. I'm using `try?` for this reason, because in your original version you were return nil anyway in the catch block. :) – Eric Aya Dec 01 '16 at 13:43