Ambiguous use of 'subscript' issue at json array [duplicate] - ios

I got this Errors after I converting to swift 2.3.
guard let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary else {
throw JSONError.ConversionFailed
}
guard
let loadedWeather = json["weather"]![0]["description"] as? String,
let loadedTemperatur = json["main"]!["temp"] as? Float,
let loadedWindSpeed = json["wind"]!["speed"] as? Float
else {
print("Weather JSON-Parsing failed")
return
}
The Ambiguous use of subscript error comes by declaring "loadedWeather, loadedTemperatur and loadedWindSpeed".
Already tried to change NSDictionary to Dictionary and other things, helped on another position in code, but here....
thanks guys

This happens because compiler doesn't know what are the intermediary object is in each of your line ... so may be
if let weather = json["weather"] as? [[String:String]], firstObject = weather.first as? [String:String]{
let loadedWeather = firstObject["description"]
}
// same for other objects i.e. `json["main"]` and `json["wind"]` with its return type

I think that the issue is that the compiler cannot work out what json["weather"] is, You may need to be more specific in your code.
Try
let loadedWeather = (json["weather"] as! [[String:AnyObject]])[0]["description"] as? String

Related

unable to access JSON array in swift

I have a JSON file and I'm trying to access the array in it.
The JSON file looks like:
{
"cars": [{
"name": "BMW",
"icons": [["front.png", "back.png", "B3"],
["front_red", "back_red", "C4"]
]
}]
}
//cars is an array of dictionaries, I just mentioned one in the snippet.
I get the JSON data as:
func loadJSONData(){
if let path = Bundle.main.path(forResource: "testJSON", ofType: "json")
{
if let jsonData = NSData(contentsOfFile : path)
{
do {
if let jsonResult = try JSONSerialization.jsonObject(with: jsonData as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String:Any]
{
self.testJSONData = (jsonResult["cars"] as? Array)!
//self.testJSONData = (jsonResult["cars"] as? Array<Dictionary<String, Any>>)! //also tried this
}
}
catch let error as NSError {
print(error.localizedDescription)
}
}
}
}
testJSONData is declared as an array:
var testJSONData = [] as [Dictionary<String, Any>]
and the error occurs when trying to get the "icons" array from the JSON.
let namePredicate = NSPredicate(format: "name like BMW")
let filteredArray :Array = testJSONData.filter() { namePredicate.evaluate(with: $0) }
let carData: Dictionary = filteredArray[0] as Dictionary<String, Any>
let carIcons: Array = carData["icons"] as! Array //error at this line
Cannot convert value of type 'Array<_>' to specified type 'Array'
Can someone please show me where I'm doing wrong ? Thanks!
Array is a generic type in Swift, so when you want to declare an array variable, you always need to specific what type of elements the Array is holding. There's no such type as Array without specifying its Element type.
Also, there's no need for type annotations in Swift, the compiler can infer the types for you and you are explicitly telling the compiler the type by casting anyways.
carIcons should be of type Array<Array<String>> or as a shorthand [[String]]
let carIcons = carData["icons"] as! [[String]]
Some general comments about your code: don't use old Foundation types, such as NSData in Swift when they have native Swift equivalents. Also don't do force unwrapping of safe casted types, that makes no sense. Either handle the casting and unwrapping safely or simply force cast if you know the cast will succeed for sure. .mutableContainers have no effect in Swift, so don't use it. There's no need to cast error to NSError in a catch block, Swift has its own Error type.
func loadJSONData(){
if let fileURL = Bundle.main.url(forResource: "testJSON", withExtension: "json") {
do {
let jsonData = try Data(contentsOfFile: fileURL)
if let jsonResult = try JSONSerialization.jsonObject(with: jsonData) as? [String:Any], let cars = jsonResult["cars"] as? [[String:Any]] {
self.testJSONData = cars
} else {
print("Unexpected JSON format")
}
}
catch {
print(error)
}
}
}
However, if you are using Swift 4, the best solution would be using the type safe Codable protocol and JSONDecoder instead of JSONSerialization.

JSONSerialization AnyObject SWIFT3 Conversion Issues

I have converted to Swift 3 and I have received the following errors when assigning to AnyObject the JSONSerialization.jsonObject. Has anyone come across this issue and know the fix?
Since the last Swift 3 update most of the return types changed from AnyObject to Any and downcast is not allowed, so in such situation you are forced to use explicit cast. That means you should make a couple of guard statements or use optional chaining if let defining each necessary field. Consider using map, filter, reduce if possible to make your code more elegant. Example:
guard way:
guard let object = try JSONSerialization.jsonObject(with: data) as? [[String: Any]] else { return nil }
guard let field1 = object[0]["field1_token"] as? [Any] else { return nil }
//do your thing
if let way:
if let object = try JSONSerialization.jsonObject(with: data) as? [[String: Any]],
let field1 = object[0]["field1_token"] as? [Any] {
//do your thing
}
You may want to check Apple's article Working with JSON in Swift
Also you can use some of the json parsing/mapping libriaries like these:
SwiftyJSON
Gloss
Please replace let object : AnyObject with let object : Any.
Error showing because of wrong casting.

How to access data in nested JSON in swift

I have a json file
I need to get the latest "id": "article" "createdAt": "2016-04-22T03:38:39.130Z" date. How do I go about getting this data from the request in swift?
Note: Sorry im a swift newb.
let url = "https://cdn.contentful.com/spaces/maz0qqmvcx21/entries?access_token=ae8163cb8390af28cd3d7e28aba405bac8284f9fe4375a605782170aef2b0b48";
var jsonData:NSData?
do{
jsonData = try NSData(contentsOfURL: NSURL(string: url)!, options: NSDataReadingOptions.DataReadingUncached)
let jsonObject:AnyObject? = try NSJSONSerialization.JSONObjectWithData(jsonData!, options: NSJSONReadingOptions.AllowFragments)
if let itemArray = jsonObject?.objectForKey("items") as? NSArray{
for item in itemArray{
if let sysItem = item.objectForKey("sys"){
//this is createdAt
if let createdAt = sysItem.objectForKey("createdAt") as? String{
print("createdAt:\(createdAt)")
}
if let contentTypeItem = sysItem.objectForKey("contentType")!.objectForKey("sys"){
//this is id
if let id = contentTypeItem.objectForKey("id") as? String{
print("id:\(id)")
}
}
}
}
}
}catch let err as NSError{
print("err:\(err)")
}
This code dosen't use any libraries,but you can use SwiftyJSON,this is will be easy to parse json.
Hope this help.
This can be done in simple way. I am assuming that you have parsed your json to dictionary
You have a key with items which is an array of dictionary and inside that dictionary you have createdAt and id(well it is deeper into the hierarchy but I will show you how to get it) keys. You can access it by simply doing this.
for dict in jsonDict["items"] as! Array<NSDictionary> {
let sysDict = dict["sys"] as! NSDictionary
print(sysDict["createdAt"]) //prints all createdAt in the array
let contentDict = sysDict["contentType"]
print((contentDict["sys"] as! NSDictionary)["id"]) // prints all ids
}
Hope this helps.

Conditional Binding Error in Swift

I am working on an example project (Written in an earlier version of Swift) in my efforts to learn Swift 2, and have run into a problem
I am getting a compile error with this -
class func loadMembersFromFile(path:String) -> [Member]
{
var members:[Member] = []
var error:NSError? = nil
if let data = NSData(contentsOfFile: path, options:[]),
json = NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary,
team = json["team"] as? [NSDictionary] {
for memberDictionary in team {
let member = Member(dictionary: memberDictionary)
members.append(member)
}
}
return members
}
The errors are:
Initializer for conditional binding must have Optional type, not 'NSData'
and
Call can throw, but it is not marked with 'try' and the error is not handled
My Swift programming experience is quite limited, so I have not been able to find a way to correct these errors. Any suggestions would be appreciated. Thanks.
Initializer for conditional binding must have Optional type, not
'NSData'
Means that you don't need conditional binding when result is not optional. But this is not true issue here. Because NSData initialiser can throw an error (which is stated in second error) and you may convert it to optional. Here is how your code will look:
class func loadMembersFromFile(path:String) -> [Member]
{
var members:[Member] = []
var error:NSError? = nil
if let data = try? NSData(contentsOfFile: path, options:[]),
json = (try? NSJSONSerialization.JSONObjectWithData(data, options: [])) as? NSDictionary,
team = json["team"] as? [NSDictionary] {
for memberDictionary in team {
let member = Member(dictionary: memberDictionary)
members.append(member)
}
}
return members
}

Swift 2 - NSJONSerialization.JSONObjectWithData with guard statement "Cannot convert value of type Element..."

I've started a Swift 2 project and I'm attempting to wrap my head around do, guard and throws. There are several other questions on Stack concerning this, but the issue I'm having is slightly different.
Here is my code:
enum JSONParsingError: String, ErrorType {
case URLCreationFailed = "Error: URL creation failed"
case SerializationFailed = "Error: JSON Parsing failed"
case DataDownloadingFailed = "Error: downloading data failed"
case DictionaryError = "Error: dictionary creation from JSON failed."
}
func fetchUserRepositories(urlString: String) throws {
do {
guard let reposURL = NSURL(string: urlString) else { throw JSONParsingError.URLCreationFailed }
guard let jsonData = NSData(contentsOfURL: reposURL) else { throw JSONParsingError.DataDownloadingFailed }
guard let jsonDictionary: NSDictionary = try NSJSONSerialization.JSONObjectWithData(jsonData, options: .MutableContainers) as? NSDictionary else { throw JSONParsingError.SerializationFailed }
guard let reposArray = jsonDictionary["repos"] as? NSDictionary else { throw JSONParsingError.DictionaryError }
for repo in reposArray {
repositories.append(TestRepo(json: repo))
}
}
}
Regardless of how I cast jsonDictionary["repos"] I keep getting the same error in my for loop:
Cannot convert value of type 'Element' (aka '(key: AnyObject, value: AnyObject)') to expected argument type 'NSDictionary' (TestRepo is just a simple class that is initialized with a dictionary. Not the most ideal way, I know).
What am I missing?
reposArray is a dictionary, that is a collection of couples (key, value). In your code:
for repo in reposArray {
repositories.append(TestRepo(json: repo))
}
repo is bound to each element in turn. So, if TestRepo expects as parameter a dictionary, it receives instead an element (a couple (key, value)), and this is the cause of the error.

Resources