I have a code to consume a REST Service but it stop working after update to swift 2.3 and iOS 10.
I'm getting error in JSON to NSMutableArray Conversion:
class func getStores(latitude:Float, longitude: Float, completion : (Array<Store>?, NSError?) -> ()) {
let latString: String = "\(latitude)"
let lonString: String = "\(longitude)"
var listStores: Array<Store> = []
let urlFull : String = ConstantHelper.baseURLStore
Alamofire.request(.GET, urlFull, parameters: ["latitude":latString, "longitude": lonString])
.responseJSON { response in
switch response.result {
case .Success:
if let repoJSON = response.result.value {
print(repoJSON)
let jsonArray = repoJSON as? NSMutableArray
for item in jsonArray! {
guard let store = Store(json: item as! JSON) else
{
print("Issue deserializing model")
return
}
listStores.append(store)
}
completion(listStores, nil)
}
break
case .Failure(let error):
completion(nil, error)
break
}
}
}
EDIT:
The error is "fatal error: unexpectedly found nil while unwrapping an Optional value"
It means that the variable jsonArray is nil. But its nil only in swift 2.3. Because the conversion json to NSMutableArray don't work more. I need to change the way I convert...but how?
There's the repoJSON value
(
{
cdState = SP;
cdStore = 100;
cdZipCode = "04029200 ";
mnStore = IBI;
noAddress = "AV IBIRAPUERA,";
noAddressAditional = " 3103 - LOJAS 4-5";
noAddressNeighborhood = " 3103";
noCity = "S\U00e3o Paulo ";
noStore = "IBI-M-C-SHOPPING IBIRAPUERA";
vlLatitude = "-23.610113";
vlLongitude = "-46.666505";
},
{
cdState = SP;
cdStore = 105;
cdZipCode = "05724900 ";
mnStore = JSU;
noAddress = "AV GIOVANNI GRONCHI, 5819 - LUC001";
noAddressAditional = "<null>";
noAddressNeighborhood = "VILA ANDRADE";
noCity = "S\U00e3o Paulo ";
noStore = "JSU-C-C-SHOPPING JARDIM SUL";
vlLatitude = "-23.630835";
vlLongitude = "-46.7359";
},
{
cdState = SP;
cdStore = 107;
cdZipCode = "05145000 ";
mnStore = TTE;
noAddress = "AV. RAIMUNDO PEREIRA DE MAGALH\U00c3ES, 1465 \U0096 LOJA \U00c2NCORA 1000";
noAddressAditional = "<null>";
noAddressNeighborhood = "JD \U00cdRIS";
noCity = "S\U00e3o Paulo ";
noStore = "TTE-PP-C-SHOPPING TIET\U00ca PLAZA";
vlLatitude = "-23.506182";
vlLongitude = "-46.718449";
},
{
cdState = SP;
cdStore = 115;
cdZipCode = "03153001 ";
mnStore = CEN;
noAddress = "AV.DR.FRANCISCO MESQUITA, 1000";
noAddressAditional = "<null>";
noAddressNeighborhood = "VILA PRUDENTE";
noCity = "S\U00e3o Paulo ";
noStore = "CEN-PP-C-CENTRAL PLAZA SHOPPING";
vlLatitude = "-23.593389";
vlLongitude = "-46.585574";
}
)
I just updated my code with
let jsonArray = repoJSON as! NSArray
Instead of
let jsonArray = repoJSON as? NSMutableArray
and it works great!
Related
I received the JSON data as shown below, I want to get the "player_name" & "player_country" from this data. How do I get this?**enter image description here
In case, the image does not load, please refer the below output:
["team_key": 2611, "team_name": Leicester, "team_badge": https://apiv2.apifootball.com/badges/2611_leicester.png, "players": <__NSArrayI 0x600003331e00>(
{
"player_age" = 33;
"player_country" = Denmark;
"player_goals" = 0;
"player_key" = 140150332;
"player_match_played" = 30;
"player_name" = "Schmeichel Kasper";
"player_number" = 1;
"player_red_cards" = 0;
"player_type" = Goalkeepers;
"player_yellow_cards" = 2;
},
{
"player_age" = 23;
"player_country" = England;
"player_goals" = 3;
"player_key" = 2242127097;
"player_match_played" = 24;
"player_name" = "Chilwell Benjamin";
"player_number" = 3;
"player_red_cards" = 0;
"player_type" = Defenders;
"player_yellow_cards" = 2;
},
{.....}
I tried the following to get required data from this:
var mainArray = [[String: Any]]()
var tryArray = [[String]]()
for i in jsonArray {
if i["team_key"] as! String == teamID {
self.mainArray.append(i)
}
}
for i in self.mainArray {
self.tryArray.append(i["player_name"] as! [String])
}
I got this error with the above code:
Fatal error: Unexpectedly found nil while unwrapping an Optional value
let playerArray:NSDictionary = json as! NSDictionary
for var player in playerArray {
self.tryArray.append(player.objectForKey("player_name") as! String)
self.tryArray.append(player.objectForKey("player_country") as! String)
}
Thank you all for your response. I have tried this and it works.
var mainArray = NSArray()
var tryArray = [[String: Any]]()
for i in jsonArray {
if i["team_key"] as! String == teamID {
self.mainArray = i["players"] as! NSArray
}
}
for i in self.mainArray {
tryArray.append(i as! [String : Any])
}
What I did was I made mainArray as NSArray instead of [[String: Any]] and then copy it to tryArray which is of actually [[String: Any]] type and used tryArray for my work.
Thanks.
I am trying to parse JSON data over the network. Below you can see where the magic is happening.
func getBookingsForDate(date: String, completionHandler: #escaping ([String:String]) -> Void ){
struct bookings: Codable {
var bookieName : String
var bookieNumber: String
var booked: String
var bookingTime: String
private enum Codingkeys: String, CodingKey{
case bookieName
case bookieNumber
case booked
case bookingTime
}
}
let params = ["date":date]
let urlString = "http://mscissorss.pythonanywhere.com/getBookings/"
Alamofire.request(urlString, method: .get, parameters: params).responseJSON {
response in
switch response.result {
case .success(let JSON):
let decoder = JSONDecoder()
guard let _ = response.data else{
return
}
do {
let loginDetails = try decoder.decode(bookings.self, from: response.data!)
print(loginDetails)
} catch let err{
print(err)
}
//let bookings = JSON as! NSDictionary
//completionHandler(JSON)
/*
do {
let decoder = JSONDecoder()
let gitData = try decoder.decode(bookings.self, from: JSON)
print(gitData.bookieName)
} catch let err {
print("Err", err)
}
*/
break
case .failure(let error):
print(error)
}
}
}
Given the code i am getting the following error message:
keyNotFound(CodingKeys(stringValue: "bookieName", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"bookieName\", intValue: nil) (\"bookieName\").", underlyingError: nil))
And the JSON response that i am getting looks like this:
{
0 = {
booked = false;
bookieName = "";
bookieNumber = "";
bookingTime = "10:00";
};
1 = {
booked = false;
bookieName = "";
bookieNumber = "";
bookingTime = "10:30";
};
10 = {
booked = false;
bookieName = "";
bookieNumber = "";
bookingTime = "15:00";
};
11 = {
booked = false;
bookieName = "";
bookieNumber = "";
bookingTime = "15:30";
};
12 = {
booked = false;
bookieName = "";
bookieNumber = "";
bookingTime = "16:00";
};
13 = {
booked = false;
bookieName = "";
bookieNumber = "";
bookingTime = "16:30";
};
14 = {
booked = false;
bookieName = "";
bookieNumber = "";
bookingTime = "17:00";
};
15 = {
booked = false;
bookieName = "";
bookieNumber = "";
bookingTime = "17:30";
};
16 = {
booked = false;
bookieName = "";
bookieNumber = "";
bookingTime = "18:00";
};
2 = {
booked = false;
bookieName = "";
bookieNumber = "";
bookingTime = "11:00";
};
}
It is the first time i am decoding so if you have an answer please try to explain a bit to why i need to make the change that i need.
UPDATE
After changing the code to what #sh_khan and #vadian suggested it worked to parse it however i am still getting this error inside my parsed object:
["1": MagicS.(unknown context at 0x106932738).bookings(bookieName: "", bookieNumber: "", booked: "false", bookingTime: "10:30"),
"0": MagicS.(unknown context at 0x106932738).bookings(bookieName: "", bookieNumber: "", booked: "false", bookingTime: "10:00"),
Also, if i want to be able to access a single value lets say the first item with the key "0" -> bookieName, how would i do that using loginDetails
Firs booked is a Bool and no need for private enum Codingkeys if you won't rename the keys
struct Booking: Codable {
let bookieName : String
let bookieNumber: String
let booked: Bool
let bookingTime: String
}
Second decode like this
let loginDetails = try decoder.decode([String:Booking].self, from: response.data!)
The root object is a dictionary with String keys and Bookings values – please name structs with a starting capital letter.
So you have to decode
let loginDetails = try decoder.decode([String:Bookings].self, from: response.data!)
I'm trying to send an array of dictionaries as one of the parameters to an Alamofire request. However, Alamofire is failing on the request.
class PromoCategory {
var promoCategoryId : Int?
var activityId : Int?
var promoCategoryName : String?
var activityName : String!
var statusCd : Int?
init() {
promoCategoryId = 0
promoCategoryName = ""
}
func getDictFormat() -> [String: Any] {
if activityId == nil { activityId = 0 }
if statusCd == nil { statusCd = 0 }
return [
"promoCategoryId" : "\(promoCategoryId!)",
"activityId" : "\(activityId!)",
"promoCategoryName" : promoCategoryName!,
"activityName" : activityName!,
"statusCd" : "\(statusCd!)"
]
}
}
var promoCat = [[String: Any]]()
for cat in promoCategories {
let element = cat.getDictFormat()
promoCat.append(element)
}
var params : [String : Any] = [:]
params["person_id"] = kPersonId
params["person_promo_id"] = promo.personPromoId
params["promo_page_id"] = promo.promoPageId
params["seq_no"] = promo.seqNo
params["promo_type"] = promoTypeString
params["page_name"] = promo.pageName
params["image_name"] = promo.imageName
params["start_date"] = promo.startDate
params["end_date"] = promo.endDate
params["website"] = promo.website
...
params["promoCategories"] = promoCat
Alamofire.request(promoUrl!, method: .post, parameters: params, encoding: JSONEncoding.default, headers: nil)
.validate()
.responseJSON { response in
switch response.result {
case .success(let data):
self.json = JSON(data)
print(self.json as Any)
DispatchQueue.main.async(execute: { () -> Void in
self.dismiss(animated: true, completion: nil)
HUD.hide()
})
case .failure(let error):
self.logApiError(url: (...)
}
}
The error:
Request failed with error:
responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(Error
Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character
0." UserInfo={NSDebugDescription=Invalid value around character 0.}))
If I remove the promoCategories parameter, then it works fine. The params object ends up looking like this:
{
address = "";
bgColorBlue = "0.28936631944444";
bgColorGreen = "0.3072916666666701";
bgColorRed = "0.3063227289789799";
city = "";
"contact_name" = "John Smith";
"contact_phone" = 3065554611;
"country_cd" = CA;
"end_date" = "2017-01-26 21:06:08Z";
"facility_name" = "Conexus Arts Centre";
"image_name" = "EV1.20170126210608302479028.jpg";
latitude = 0;
longitude = 0;
"page_name" = "Test Promo";
"person_id" = 1;
"person_promo_id" = 21;
promoCategories = (
{
activityId = 68;
activityName = "Fashion & Beauty";
promoCategoryId = 271;
promoCategoryName = Accessories;
statusCd = 0;
},
{
activityId = 68;
activityName = "Fashion & Beauty";
promoCategoryId = 273;
promoCategoryName = Beauty;
statusCd = 0;
},
{
activityId = 68;
activityName = "Fashion & Beauty";
promoCategoryId = 270;
promoCategoryName = Fashion;
statusCd = 0;
}
);
"promo_page_id" = 0;
"promo_type" = event;
"prov_state_cd" = "";
"seq_no" = 0;
"start_date" = "2017-01-26 21:06:08Z";
website = "";
}
Is this the approach I should be using? Is there something I have missed? Thanks.
I new to Alamofire, I was testing out some API. I came across foreign exchange rates. So the JSON file is like this
["base": CAD, "date": 2016-12-01, "rates": {
AUD = "1.0097";
BGN = "1.3735";
BRL = "2.57";
CHF = "0.7559";
CNY = "5.1388";
CZK = "19.004";
DKK = "5.2248";
EUR = "0.70225";
GBP = "0.59058";
HKD = "5.7881";
HRK = "5.2985";
HUF = "220.48";
IDR = 10108;
ILS = "2.8607";
INR = "51.009";
JPY = "85.246";
KRW = "871.9400000000001";
MXN = "15.403";
MYR = "3.331";
NOK = "6.2941";
NZD = "1.0539";
PHP = "37.102";
PLN = "3.1374";
RON = "3.1631";
RUB = "47.591";
SEK = "6.8775";
SGD = "1.0657";
THB = "26.616";
TRY = "2.6006";
USD = "0.7462800000000001";
ZAR = "10.504";}]
typealias JSONStandard = [String: AnyObject]
func parseData(JSONData:Data) {
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONStandard
if let rates = readableJSON["rates"] as? JSONStandard{
for i in 0..<rates.count {
let rate = rates[i] as! //Here
}
print(rates)
}
print(readableJSON)
} catch {
print(error)
}
}
I was able to get side "rates" but I don't get how I would parse all the data inside the "rates". I thought I would have to save it inside a dictionary. very confused Thanks
As you can see it's a double value in String, so you need to convert AnyObject to String first, then convert it to Double. You can do it like this (Tested in Swift playground) :
import Foundation
typealias JSONStandard = [String: AnyObject]
func parseData(JSONData:Data) {
do {
guard let readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as? JSONStandard,
let ratesJSON = readableJSON["rates"] as? JSONStandard
else { return }
print("Readable JSON :")
print(readableJSON)
let rates = ratesJSON.flatMap({ (key, value) -> ([String: Double]) in
guard let value = value as? String, let convertedValue = Double(value) else { return [:] }
return [key: convertedValue]
})
print("Rates :")
print(rates)
} catch {
print(error)
}
}
let jsonString = "{\"base\": \"CAD\", \"date\": \"2016-12-01\", \"rates\": { \"AUD\": \"1.0097\", \"BGN\": \"1.3735\", \"BRL\": \"2.57\"}}"
let jsonData = jsonString.data(using: String.Encoding.utf8)!
parseData(JSONData: jsonData)
Result :
Readable JSON :
["base": CAD, "date": 2016-12-01, "rates": {
AUD = "1.0097";
BGN = "1.3735";
BRL = "2.57";
}]
Rates :
[("BGN", 1.3734999999999999), ("AUD", 1.0097), ("BRL", 2.5699999999999998)]
You have to save it into an array of Double:
var yourArray = [Double]()
for i in 0..<rates.count {
let rate = rates[i] as! Double
print(rate)
yourArray.append(rate)
}
print(yourArray.description)
I get a error: "fatal error: unexpectedly found nil while unwrapping an Optional value" when I try to pass the result of the JSON into an array. I think that the problem is when I try to get the geo coordinate: lat and long into my variables.
Please can somebody help me with this issue?
The code for the passing de result of the JSON to an array is:
ViewController.swift
import UIKit
import MapKit
import Alamofire
class ViewController: UIViewController {
var artworks = [Artwork]()
#IBOutlet weak var mapView: MKMapView!
let initialLocation = CLLocation(latitude: 52.370216, longitude: 4.895168)
let regionRadius: CLLocationDistance = 6000
override func viewDidLoad() {
super.viewDidLoad()
centerMapOnLocation(initialLocation)
getData()
mapView.addAnnotations(artworks)
mapView.delegate = self
}
func getData() {
Alamofire.request(.GET , "http://kaart.amsterdam.nl/datasets/datasets-item/t/kunstwerken-in-de-openbare-ruimte/export/json").responseJSON() {
(_, _, json, _) in
println(json)
var json = JSON(json!)
if let appArray = json["features"].array {
for artObject in appArray {
let title = artObject["properties"]["titel"].string
let locationName = artObject["properties"]["titel_key"].string
let discipline = artObject["properties"]["titel_key"].string
let latitude = (artObject["geometry"]["coordinates"].string! as NSString).doubleValue
let longitude = (artObject["geometry"]["coordinates"].string! as NSString).doubleValue
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
var openArt1 = Artwork(title: title!, locationName: locationName!, discipline: discipline!, coordinate: coordinate)
self.artworks.append(openArt1)
self.mapView.addAnnotations(self.artworks)
}
}
}
}
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate, regionRadius * 2.0, regionRadius * 2.0)
mapView.setRegion(coordinateRegion, animated: true)
}
the result of the JSON looks like this:
Optional({
features = (
{
geometry = {
coordinates = (
"4.9305202013246",
"52.363277804149"
);
type = Point;
};
properties = {
adres = "";
content = "";
"content_src" = "";
"date_created" = "2015-05-16 00:07:58";
"date_modified" = "<null>";
datum = "2013-10-09 17:15:00";
email = "";
"id_2" = "";
"link_href" = "";
locatie = "POINT(4.93052020132461 52.363277804148602)";
omschrijving = "";
plaats = "";
postcode = "";
published = "";
summary = "";
"summary_type" = "";
telefoonnummer = "";
titel = "101 namen - 136602";
"titel_key" = "101_namen_136602";
title = "";
type = Kunstwerk;
updated = "";
website = "http://www.amsterdam.nl/kunstencultuur/kunst-openbare/kunst-openbare/kunstwerken/amsterdam-stadsdeel-0/dapperbuurt/101-namen-136602/";
};
artObject["geometry"]["coordinates"] is an Array of Doubles, not a String.
If you println the JSON response it could be confusing as you see the Doubles wrapped into quotes (") but it is an array of Doubles nonetheless in the JSON for the "coordinates" key.
UPDATE:
I just checked and they are Doubles:
var err: NSError?
let data = NSData(contentsOfURL: NSURL(string: "http://kaart.amsterdam.nl/datasets/datasets-item/t/kunstwerken-in-de-openbare-ruimte/export/json")!)
let json = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.allZeros, error: &err) as! [String:AnyObject]
let features = json["features"] as! [[String:AnyObject]]
let object1 = features[0]
let geo = object1["geometry"]?["coordinates"] as! [Double]
let lat = geo[0] // 4.9305202013246
let lon = geo[1] // 52.363277804149
You just have to access these values with SwiftyJSON like this in your loop:
let coo = artObject["geometry"]["coordinates"].array!
let latitude = coo[0].doubleValue
let longitude = coo[1].doubleValue