I try to get start with swiftyJSON and parsing information in Swift so i start with this API to understand it:
http://api.androidhive.info/contacts/
So here is my Code
import Fuzi
import UIKit
import Alamofire
import SwiftyJSON
class ViewController: UIViewController {
var arrRes = [[String:AnyObject]]() //Array of dictionary
var JSON_TestURL = "http://api.androidhive.info/contacts/"
override func viewDidLoad() {
super.viewDidLoad()
//get JSON
Alamofire.request(.GET, JSON_TestURL).responseJSON { (responseData) -> Void in
let swiftyJsonVar = JSON(responseData.result.value!)
//print(swiftyJsonVar)
//get JSONarray Name and write it into new Array
if let resData = swiftyJsonVar["contacts"].arrayObject {
self.arrRes = resData as! [[String:AnyObject]]
}
//count array and give "tag"
print(self.arrRes.count)
for var index = 0; index < self.arrRes.count; ++index {
var dict = self.arrRes[index]
let x = dict["name"] as? String
print(x)
print("")
}
}
}
getting the name, id etc is no problem but when i try to get the phone number i can't find a way.
for var index = 0; index < self.arrRes.count; ++index {
var dict = self.arrRes[index]
let x = dict["phone"]!["mobile"] as? String
print(x)
//print("")
}
When using SwiftyJSON you don't have to cast the objects like you do with NSJSONSerialization. You don't have to use this way of looping either when a simple call to map will do the trick.
For example, replace all this:
if let resData = swiftyJsonVar["contacts"].arrayObject {
self.arrRes = resData as! [[String:AnyObject]]
}
print(self.arrRes.count)
for var index = 0; index < self.arrRes.count; ++index {
var dict = self.arrRes[index]
let x = dict["phone"]!["mobile"] as? String
print(x)
}
with this:
let contacts = swiftyJsonVar["contacts"].arrayValue
let allMobilePhones = contacts.map { $0["phone"]["mobile"].stringValue }
print(allMobilePhones)
Related
I am trying to get data from Json url for this specific line "ConfirmedCount" from https://raw.githubusercontent.com/BlankerL/DXY-COVID-19-Data/master/json/DXYOverall.json to a UiLabel that I created but keeps getting error. I have been trying to do this for week now.
Here is my code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var labeltest: UILabel!
//the json file url
let URL_HEROES = "https://raw.githubusercontent.com/BlankerL/DXY-COVID-19-Data/master/json/DXYOverall.json";
//the label we create
#IBOutlet weak var labelTest: UILabel!
//A string array to save all the names
var nameArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
//calling the function that will fetch the json
getJsonFromUrl()
}
//this function is fetching the json from URL
func getJsonFromUrl(){
//creating a NSURL
let url = NSURL(string: URL_HEROES)
//fetching the data from the url
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary {
//printing the json in console
print(jsonObj.value(forKey: "results")!)
//getting the avengers tag array from json and converting it to NSArray
if let heroeArray = jsonObj.value(forKey: "results") as? NSArray {
//looping through all the elements
for results in heroeArray{
//converting the element to a dictionary
if let heroeDict = results as? NSDictionary {
var confirmedCount: Int
//getting the name from the dictionary
if let confirmedCount = heroeDict.value(forKey: "confirmedCount") {
//adding the name to the array
self.nameArray.append((String (format: "1234", confirmedCount as! Int)))
}
}
}
}
OperationQueue.main.addOperation({
//calling another function after fetching the json
//it will show the names to label
self.showNames()
})
}
}).resume()
}
func showNames(){
//looping through all the elements of the array
for confirmedCount in nameArray{
labelTest.text = (confirmedCount)
}
}
}
This is the error that I am getting:
(
{
abroadRemark = "";
confirmedCount = 80422;
confirmedIncr = 120;
curedCount = 49923;
curedIncr = 2663;
currentConfirmedCount = 27515;
currentConfirmedIncr = "-2581";
deadCount = 2984;
deadIncr = 38;
generalRemark = "\U7591\U4f3c\U75c5\U4f8b\U6570\U6765\U81ea\U56fd\U5bb6\U536b\U5065\U59d4\U6570\U636e\Uff0c\U76ee\U524d\U4e3a\U5168\U56fd\U6570\U636e\Uff0c\U672a\U5206\U7701\U5e02\U81ea\U6cbb\U533a\U7b49";
note1 = "\U75c5\U6bd2\Uff1aSARS-CoV-2\Uff0c\U5176\U5bfc\U81f4\U75be\U75c5\U547d\U540d COVID-19";
note2 = "\U4f20\U67d3\U6e90\Uff1a\U65b0\U51a0\U80ba\U708e\U7684\U60a3\U8005\U3002\U65e0\U75c7\U72b6\U611f\U67d3\U8005\U4e5f\U53ef\U80fd\U6210\U4e3a\U4f20\U67d3\U6e90\U3002";
note3 = "\U4f20\U64ad\U9014\U5f84\Uff1a\U7ecf\U547c\U5438\U9053\U98de\U6cab\U3001\U63a5\U89e6\U4f20\U64ad\U662f\U4e3b\U8981\U7684\U4f20\U64ad\U9014\U5f84\U3002\U6c14\U6eb6\U80f6\U4f20\U64ad\U548c\U6d88\U5316\U9053\U7b49\U4f20\U64ad\U9014\U5f84\U5c1a\U5f85\U660e\U786e\U3002";
remark1 = "\U6613\U611f\U4eba\U7fa4\Uff1a\U4eba\U7fa4\U666e\U904d\U6613\U611f\U3002\U8001\U5e74\U4eba\U53ca\U6709\U57fa\U7840\U75be\U75c5\U8005\U611f\U67d3\U540e\U75c5\U60c5\U8f83\U91cd\Uff0c\U513f\U7ae5\U53ca\U5a74\U5e7c\U513f\U4e5f\U6709\U53d1\U75c5";
remark2 = "\U6f5c\U4f0f\U671f\Uff1a\U4e00\U822c\U4e3a 3\Uff5e7 \U5929\Uff0c\U6700\U957f\U4e0d\U8d85\U8fc7 14 \U5929\Uff0c\U6f5c\U4f0f\U671f\U5185\U53ef\U80fd\U5b58\U5728\U4f20\U67d3\U6027\Uff0c\U5176\U4e2d\U65e0\U75c7\U72b6\U75c5\U4f8b\U4f20\U67d3\U6027\U975e\U5e38\U7f55\U89c1";
remark3 = "\U5bbf\U4e3b\Uff1a\U91ce\U751f\U52a8\U7269\Uff0c\U53ef\U80fd\U4e3a\U4e2d\U534e\U83ca\U5934\U8760";
remark4 = "";
remark5 = "";
seriousCount = 6416;
seriousIncr = "-390";
suspectedCount = 520;
suspectedIncr = 143;
updateTime = 1583295001876;
}
)
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file /Users/AbdalQaydi/Desktop/jnews/jnews/ViewController.swift, line 84
2020-03-04 00:26:49.829895-0500 jnews[12702:1192396] Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file /Users/AbdalQaydi/Desktop/jnews/jnews/ViewController.swift, line 84
(lldb)
It looks like it can parse the data but I don't know how to add the json data for line "confirmedCount" to label.
Please any help is really appreciated. I have been trying to figure out how to do this and just can't find a way.
Use Codable to parse the JSON data.
Models:
struct Root: Decodable {
let results: [Result]
let success: Bool
}
struct Result: Decodable {
let currentConfirmedCount, confirmedCount, suspectedCount, curedCount: Int
let deadCount, seriousCount, currentConfirmedIncr, confirmedIncr: Int
let suspectedIncr, curedIncr, deadIncr, seriousIncr: Int
let generalRemark, abroadRemark, remark1, remark2: String
let remark3, remark4, remark5, note1: String
let note2, note3: String
let updateTime: Int
}
Parse the data like,
if let url = URL(string: URL_HEROES) {
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let data = data {
do {
let response = try JSONDecoder().decode(Root.self, from: data)
let confirmedCountArr = response.results.map { String($0.confirmedCount) }
nameArray.append(contentsOf: confirmedCountArr)
//rest of the code...
} catch {
print(error)
}
}
}.resume()
}
I've been using JSONParsing to display my data when you search for a term. Now I want to list out all of those terms in an alphabetized list. But am having trouble getting the code to work correctly. I've replicated some code from someone else that was having the same problem and got that to work but I'm having trouble implementing my own code.
I currently am parsing my JSON with this code:
func parseJSONSignDictionary() {
if let url = Bundle.main.url(forResource: "csvjson", withExtension: "json") {
do {
let date = Date()
let data = try Data(contentsOf: url)
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String:Any] {
(json["results"] as? [[String:Any]])?.forEach { j in
if let name = j["identifier"] as? String, let id = j["id"] as? Int {
let sign = Signs(name: name, number: id)
signsArray.append(sign)
}
}
}
print("Took", Date().timeIntervalSince(date))
} catch {
print(error.localizedDescription)
}
}
}
Edit to add some more code, this is my Signs class, which would replace the Restaurant Array/Class:
class Signs: NSObject, Decodable, NSCoding {
private var _signName: String!
private var _signNumber: Int!
var signName: String {
return _signName
}
var signNumber: Int {
return _signNumber
}
func encode(with aCoder: NSCoder) {
aCoder.encode(signName, forKey: "signNameKey")
}
required init?(coder aDecoder: NSCoder) {
print("Trying to turn Data into Sign")
self._signName = aDecoder.decodeObject(forKey: "signNameKey") as? String
}
init(name: String, number: Int) {
self._signName = name
self._signNumber = number
}
}
The code from another StackOverflow that I'm trying to use is from here. question:Display data from JSON in alphabetical sections in Table View in Swift
func makeDataSource(names:[String:[AnyObject]]) {
var dict = [String:[Restaurant]]()
let letters = NSCharacterSet.letters
for (_,value) in names {
//Iterating Restaurants
for resObj in value {
if let restaurantName = resObj["name"] as? String {
let restaurant = Restaurant(name: restaurantName)
var key = String(describing: restaurant.name.first!)
//To check whether key is alphabet or not
key = isKeyCharacter(key: key, letters: letters) ? key : "#"
if let keyValue = dict[key] {
//Already value exists for that key
var filtered = keyValue
filtered.append(restaurant)
//Sorting of restaurant names alphabetically
//filtered = filtered.sorted(by: {$0.0.name < $0.1.name})
dict[key] = filtered
} else {
let filtered = [restaurant]
dict[key] = filtered
}
}
}
}
//To sort the key header values
self.dataArray = Array(dict).sorted(by: { $0.0 < $1.0 })
//Logic to just shift the # category to bottom
let temp = self.dataArray[0]
self.dataArray.removeFirst()
self.dataArray.append(temp)
self.indexTitles = Array(dict.keys.sorted(by: <))
let tempIndex = self.indexTitles[0]
self.indexTitles.removeFirst()
self.indexTitles.append(tempIndex)
}
I have my own array that would replace Restaurant, called Signs.
if let restaurantName = resObj["name"] as? String {
I'm also wondering where this "name" is being pulled from? Is it the array/model which has the var name?
I'm not sure since I have a way to access the JSON data with my own function if I even need to try to use the getdata() function.
I just wanna understand what I'm missing, and how to do it on my own to get the code to work properly.
I have two Realm tables declared:
class Task: Object {
dynamic var taskID: String = ""
let taskAssignedTo = List<Contacts>()
}
class Contacts: Object {
dynamic var contactEmail: String = ""
dynamic var contactName: String = ""
}
Final goal is to convert the Task Realm object into JSON. The method I'm thinking of is:
Convert the object to a dictionary using a method within the class
func taskToDictionary() -> [String: AnyObject] {
return [
"taskID" : self.taskID,
"taskAssignedTo" : self.taskAssignedTo._rlmArray.count //Not sure how to get the array
]
}
Convert the resulting dictionary into JSON with SwiftyJSON
let taskObject = Task()
let newTaskJSON = JSON(taskObject.taskToDictionary())
Right now, this converts ok, but:
Is there a better way to do this?
How can I convert the RLMArray into an array for JSON conversion?
Managed to find the answer here:
Can I serialize a RealmObject to JSON or to NSDictionary in Realm for Swift?
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dictionary = self.dictionaryWithValuesForKeys(properties)
var mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeysWithDictionary(dictionary)
for prop in self.objectSchema.properties as [Property]! {
// find lists
if let objectClassName = prop.objectClassName {
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase {
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
if let object = nestedListObject._rlmArray[index] as? Object {
objects.append(object.toDictionary())
}
}
mutabledic.setObject(objects, forKey: prop.name)
}
}
}
return mutabledic
}
}
Update for Xcode 7 & Swift 2:
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dictionary = self.dictionaryWithValuesForKeys(properties)
let mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeysWithDictionary(dictionary)
for prop in self.objectSchema.properties as [Property]! {
// find lists
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase {
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
let object = nestedListObject._rlmArray[index] as AnyObject
objects.append(object.toDictionary())
}
mutabledic.setObject(objects, forKey: prop.name)
}
}
return mutabledic
}
}
Update to Xcode 8 and Swift 3 :
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dictionary = self.dictionaryWithValues(forKeys: properties)
let mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeys(dictionary)
for prop in self.objectSchema.properties as [Property]! {
// find lists
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase {
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
let object = nestedListObject._rlmArray[index] as AnyObject
objects.append(object.toDictionary())
}
mutabledic.setObject(objects, forKey: prop.name as NSCopying)
}
}
return mutabledic
}
}
As i can't comment, #Eric
Based on #Eugene Teh answer
I had to do a specific treatment for date. Here is my code (swift 3)
I get the value first
if let value = self.value(forKey: props.name) {
if props.type == .date {
mutabledic[props.name] = (value as! Date).timeIntervalSince1970
//for using like the example, this should work
//mutabledic.setObject( (value as! Date).timeIntervalSince1970, forKey: prop.name as NSCopying)
}
[..]//other case
}
Swift 4.2 Xcode 11
This is how i solved the issue. To covert Realm Objects into JSON Array for sending to the Rest APIs
Requirement - SwiftyJSON
func getJsonArray(){
var dicArray = [Dictionary<String,AnyObject>]()
for item in cartsData! {
dicArray.append(item.toDictionary())
}
print(JSON(dicArray))
}
cartsData - var cartsData : Results<...>?
extension Object {
func toDictionary() -> [String:AnyObject] {
let properties = self.objectSchema.properties.map { $0.name }
var dicProps = [String:AnyObject]()
for (key, value) in self.dictionaryWithValues(forKeys: properties) {
//key = key.uppercased()
if let value = value as? ListBase {
dicProps[key] = value.toArray1() as AnyObject
} else if let value = value as? Object {
dicProps[key] = value.toDictionary() as AnyObject
} else {
dicProps[key] = value as AnyObject
}
}
return dicProps
}
}
extension ListBase {
func toArray1() -> [AnyObject] {
var _toArray = [AnyObject]()
for i in 0..<self._rlmArray.count {
let obj = unsafeBitCast(self._rlmArray[i], to: Object.self)
_toArray.append(obj.toDictionary() as AnyObject)
}
return _toArray
}
}
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
So I set up some data from an API to create a managed object, How do I determine whether the managed object already exists (in my example, every object has a unique id), and create it if it does not.
// set up core data
var appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
var context:NSManagedObjectContext = appDel.managedObjectContext!
// Get data from API
let urlPath = "http://www.example.com"
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
let getMovies = session.dataTaskWithURL(url!, completionHandler: {
data, response, error -> Void in
if error != nil {
println(error)
} else {
// Parse the JSON data from API
var moviesResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary
if let subjects = moviesResult["subjects"] as? [[NSObject:AnyObject]] {
var movies = [[String:NSString]()]
var movie:AnyObject
var newMovieItem:NSManagedObject
// Loop through the arrays returned by API to get each movie
for (var i = 0 ; i < subjects.count ; i++) {
// Initialize the movies array
movies.append([String:NSString]())
movie = subjects[i] as NSDictionary
movies[i]["title"] = movie["title"] as? NSString
movies[i]["id"] = movie["id"] as? NSString
newMovieItem = NSEntityDescription.insertNewObjectForEntityForName("Movies", inManagedObjectContext: context) as! NSManagedObject
newMovieItem.setValue(movies[i]["title"], forKey: "title")
newMovieItem.setValue(movies[i]["id"], forKey: "id")
context.save(nil)
}
var request = NSFetchRequest(entityName: "Movies")
request.returnsObjectsAsFaults = false
var results = context.executeFetchRequest(request, error: nil)
}
}
})
getMovies.resume()