1

I have JSON like this but with more data:

[
  {
    "name": "Place 1",
    "avatar": "https://sometext.it/image=1",
    "id": "1",
    "lng": 10.01,
    "lat": 15.02
  },
  {
    "name": "Place 2",
    "avatar": "https://sometext.it/image=2",
    "id": "2",
    "lng": 15.02,
    "lat": 15.03
  }
]

I get JSON from URL and I want to insert them to array of places. I have class:

class Place {
    var Avatar = ""
    var Id = 0
    var Lat = 0.0
    var Lng = 0.0
    var Name = ""

    required init(avatar: String, id: Int, lat: Double, lng: Double, name: String) {
        self.Avatar = avatar
        self.Id = id
        self.Lat = lat
        self.Lng = lng
        self.Name = name
    }
}

And i create an Array:

var places: [Place] = []

I serialize JSON like this:

func parsingJson() {
        guard let url = URL(string: "https://somelink.com") else {
            return
        }

        let session = URLSession.shared
        session.dataTask(with: url) { (data, response, error) in

            if let response = response {
                print(response)
            }

            if let data = data {
                print(data)
                do {
                    let json = try JSONSerialization.jsonObject(with: data, options: [])

                    for result in json as! [[String:Any]] {
                        let avatar = result["avatar"] as! String
                        let id = result["id"] as! Int
                        let lat = result["lat"] as! Double
                        let lng = result["lng"] as! Double
                        let name = result["name"] as! String

                            let place = Place(avatar: avatar, id: id, lat: lat, lng: lng, name: name)
                            self.places.append(place)
                           print(result)
                    }

                }catch {
                    print("JSON Error")
                }
            }
        }.resume()
    }

but that doesn't work, I have error like this: http://obrazki.elektroda.pl/9267167800_1497627255.png

I know that I have nil but I don't know why :( When I print the JSON when I'm serialising I see it on console.

Hamish
  • 78,605
  • 19
  • 187
  • 280
jabbla92
  • 23
  • 4
  • Possible duplicate of [Correctly Parsing JSON in Swift 3](https://stackoverflow.com/questions/39423367/correctly-parsing-json-in-swift-3) – Dávid Pásztor Jun 16 '17 at 15:37

2 Answers2

0

You haven't nil, read error - Could not cast value of type NSTaggedPointerString to NSNumber This means that your id is String and you are casting it to Int so replace

let id = result["id"] as! Int 

to

let id = result["id"] as! String
Arthur Sahakyan
  • 566
  • 3
  • 17
0

The first, you are trying to get ID as an INT, when your JSON Object is showing that it's a string.. So you would need to do:

var id = Int()
if let someID = result["id"] as? String {
   id = Int(someId)
} else {
   print("ID failed as String")
}

However, i'd also recommend using a guard statement before your for loop:

guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [[String:Any]] else {
   print("Invalid json object type")   
   return
}


for result in json {
///your code.
}

you at least try to unwrap the variable, and get some Int instance to pass along

But obviously, the simpler solution would be to save the id field in your JSON to the type you would want on your front-end.. in this case a Number.

While it might not look as clean as your code, use unwraping methods like guards, and if-else logics as much as possible, and create failed unwrap fallbacks as much as possible as early on in your project. It helps in debugging down the line and creates a good base when your project becomes large enough. Check up on Apple's guide and this here for some good starting points.

Late update, but re-reading on all this landed me on this neat article by Apple: https://developer.apple.com/swift/blog/?id=37

jlmurph
  • 1,050
  • 8
  • 17
  • Thank a lot, now it works, but how now i can't use this array out of clousure for example i write simple function to print data : func printPlace() { for result in places{ print(result.Name) } } and it don't work, when I want to print places[2].Name there is an error thai is out of range. How can i use the data from JSON from another place in code, not only in the closure ? – jabbla92 Jun 16 '17 at 16:16
  • You mean, you would like to use the json from the network task outside of the parsingJSON() method? – jlmurph Jun 16 '17 at 16:19
  • I create an array of Place objects and in the code i write self.places.append(place) but i can use from that array only in the clousure, I want to use data from this array in another function – jabbla92 Jun 16 '17 at 16:23
  • There is a screen: **http://obrazki.elektroda.pl/9563215100_1497630364.png** The printPlace function don't print anything, error on the console is about rendering map, it doesn't matter – jabbla92 Jun 16 '17 at 16:27
  • Well, if you are using the JSON object you've shown on your question, it only has two elements in it.. you're getting index out of range because when calling places[2], it's looking for a third element which does not exist. Array elements are positioned starting at 0, not at 1 like you are assuming. So, your places array has 2 elements, but the first one is at places[0], and the second one is at places[1]. Arrays in all programming languages work this way. Reminder: if n = (length of any array), then the last element is at n - 1, and the first one is at 0. – jlmurph Jun 16 '17 at 16:34
  • So your places objects are there, you're just not accessing the array properly. Read this here, the first picture shows you what i mean : https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html . The Array box has 5 elements, but the indexes to access them only go up to the number 4 (5 -1 = 4)! :) – jlmurph Jun 16 '17 at 16:35
  • Sorry, I mislead You, I gave JSON example with 2 elements, in my code I have 10 elements :) and I still can't get data out from clousure even if I want places[0] there still anything in array :( I think that is problem with self.places.apped ? because when I print elements after that there is no problem. Only if i want to get to elements out of function there isn't anything i array – jabbla92 Jun 16 '17 at 16:56
  • Hmm i cant seem to recreate that issue with what you've shown me :/ . Are you sure your network task, or the try json isn't failing? You'd have to show me where you're trying to access the values, and when. I'm saying this because the updated for-loop, the array, and your printPlaces() methods work. So it must be something beyond what you've shown, or it's an instantiation/timing issue with when you are trying to get the value (as in perhaps before you populate the array?) – jlmurph Jun 16 '17 at 17:20
  • Well, again, where are you calling printPlaces()? – jlmurph Jun 16 '17 at 18:52
  • Out of parsingJson function, this is an example, I want to use an places array everywhere in code not only in pasingJson function. My idea was that i serialise and parse Json itno array of object. – jabbla92 Jun 16 '17 at 21:04
  • Are you trying to acces the array from another class? – jlmurph Jun 16 '17 at 22:32
  • Yes, I want, but I made my array global in ViewController. – jabbla92 Jun 17 '17 at 06:40