Error JSONSerialization

Hi,


I have the following code:


import UIKit


class ViewController: UIViewController {


//Our web service url

let URL_GET_TEAMS:String = "http://localhost/MyWebService/api/getteams.php"


override func viewDidLoad() {

super.viewDidLoad()

// Do any additional setup after loading the view, typically from a nib.

//created NSURL

let requestURL = NSURL(string: URL_GET_TEAMS)


//creating NSMutableURLRequest

let request = NSMutableURLRequest(URL: requestURL!)

//setting the method to post

request.HTTPMethod = "GET"

//creating a task to send the post request

let task = NSURLSession.sharedSession().dataTaskWithRequest(request){

data, response, error in

//exiting if there is some error

if error != nil{

print("error is \(error)")

return;

}

//parsing the response

do {

//converting resonse to NSDictionary

var teamJSON: NSDictionary!

teamJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary

//getting the JSON array teams from the response

let teams: NSArray = teamJSON["teams"] as! NSArray

//looping through all the json objects in the array teams

for i in 0 ..< teams.count{

//getting the data at each index

let teamId:Int = teams[i]["id"] as! Int!

let teamName:String = teams[i]["name"] as! String!

let teamMember:Int = teams[i]["member"] as! Int!

//displaying the data

print("id -> ", teamId)

print("name -> ", teamName)

print("member -> ", teamMember)

print("===================")

print("")


}

} catch {

print(error)

}

}

//executing the task

task.resume()

}

override func didReceiveMemoryWarning() {

super.didReceiveMemoryWarning()

// Dispose of any resources that can be recreated.

}

}


I'm getting these errors:


let teamName:String = teams[i]["name"] as! String! >> Type 'Any' has no subscript members

let teamMember:Int = teams[i]["age"] as! Int! >> Type 'Any' has no subscript members


How can I solve the errors?


Tks!

Replies

Your teams instance is typed as an NSArray which only contains objects of the Any type.

You will need to give an explicit type for what you expect to get out of the array, before you can use it.


For example: (only tested to compile)

//looping through all the json objects in the array teams
for i in 0 ..< teams.count{

    let team = teams[i] as! NSDictionary

    //getting the data at each index
    let teamId:Int = team["id"] as! Int!
    let teamName:String = team["name"] as! String!
    let teamMember:Int = team["member"] as! Int!

    /* ... */
}

Hi!

Thanks for the feedback! But it still has an error:


Cannot convert value of type ‘String’to expected argument type ‘Int’


If you are using the change I posted, double check that you changed "teams[i]" to "team" and not "teams" on the line where you get that error.


If that isn't it, you'll need to post your current code, and let us know which line the error is coming from.

I made the correction and now has this error:


Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}

That error means that the issue is either a networking problem or an issue with the JSON data being received, rather than an issue with your Swift code.


You can try logging the data that was returned before trying to parse it as JSON to see if there is an obvious problem. It may be something that needs to be fixed in the server/source of the JSON data.


Adding the .AllowFragments option to your NSJSONSerialization.JSONObjectWithData() call as suggested by the error message might work if the JSON data you're receiving is only slightly malformed.

I added "options: JSONSerialization.ReadingOptions.allowFragments" and now gave another code error:

Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}


The code below how it is



/ do {

/

var teamJSON: NSDictionary!

teamJSON = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments) as? NSDictionary

/

let teams: NSArray = teamJSON["sqltable"] as! NSArray

/

for i in 0 ..< teams.count{

let team = teams[i] as! NSDictionary

/

let teamName:String = team["name"] as! String!

let teamAge:String = team["age"] as! String!

/

print("name -> ", teamName)

print("age -> ", teamAge)

print("===================")

print("")

}

If you add

print("data received is \(data!.length) bytes:\n\(data!)")

before attempting the JSON serialization, what does it tell you about the data you received?

Note that if this is a Swift

Data
value you should add
as NSData
to your logging so that you get a hex dump of the bytes.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I am facing similar issue....

Error:

underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code👨 840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}

Question

I know that using using JSONDecoder we can convert the downloaded JSON data into class/struct object.

Is there a way to do the same for raw data(NSData)/octect. Since downloaded is not a json, I am getting error. I have class like this

Code

public struct FileData: Codable{ public var data: Data? public init (data: Data? = nil){ self.data = data } } Is there a way to assign the downloaded data to FileData().data via decoding

extension Data { func decode() -> Result<T, Error> where T: Codable { do { let decoder = JSONDecoder() let object: T = try decoder.decode(T.self, from: self)  return Result.success(object) } catch { return Result.failure(error) } }

Expectation:

Here T is FileData. I using REST Get api to download(octet stream) a file data and want to set it to FileData().data. It seems like raw data can't be Codable? Is that true? If so, I think I need to manually assign the downloaded data to FileData().data