I am trying to fetch data from JSON into UIPickerview but i don't the format for parsing that data and fetch it from picker.
I need to get name and code from parsed data in my pickerview when i tap the textfield
Parsed code
let url = URL(string: "http://api.railwayapi.com/v2/name-to-code/name/\. (pickTxtField.text!)/apikey/fe22em16kb")! //change the url
let session = URLSession.shared
let request = URLRequest(url: url)
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
guard error == nil else { return
}
guard let data = data else { return
}
do {
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
{
DispatchQueue.main.async
{
var display = String(describing: json["stations"]!)
let realname = json["code"]
let departmentName = json["name"]
self.department.append(departmentName! as! String)
self.pickView.reloadAllComponents() // this is reference to your pickerView. Make it global and use it
}
}
}catch let error {
print(error.localizedDescription) }
})
task.resume()
You need to fetch the data from api which will most probably be an array. Implement the datasource of UIPickerView, number of rows equal to the size of that array and show title for each row from the array at respective index.
Related
So i received some json data from a server now am trying to save it as an array so i can populate a tableview with it but am having a trouble doing it here is my code :
class UserInfo : UIViewController{
var main = ""
session.dataTask(with: url) { (data, response, error) in
if let response = response {
print (response)
}
if let data = data {
let json = (try? JSONSerialization.jsonObject(with: data, options: []))
print(json)
guard let array = json as? [Any] else {return}
for info in array {
guard let infoDict = info as? [String : Any] else{return}
//there is a declared var called main
//main is the one i want save as an array, currently its a variable. i tried to save it as an array by using as! Array but i get error
self.main = infoDict["Title"] as! String
print (self.main)
}
}
}.resume()
}
First you have to declare ary outside of the request scope. Then you have to store your data in the same ary.
var ary: NSMutableArray = NSMutableArray()
session.dataTask(with: url) { (data, response, error) in
if let response = response {
print (response)
}
if let data = data {
let json = (try? JSONSerialization.jsonObject(with: data, options: []))
print(json)
guard let array = json as? [Any] else {return}
for info in array {
guard let infoDict = info as? [String : Any] else{return}
//there is a declared var called main
//main is the one i want save as an array, currently its a variable. i tried to save it as an array by using as! Array but i get error
self.main = infoDict["Title"] as! String
self.ary.add(self.main)
print (self.main)
}
print("Final array is :::",self.ary)
}
}.resume()
Try above code. Hope it will work for you.
Have been researching on the parsing for quite a bit. With plethora of information avilable for JSON nothing seems to explain how to do in a sensible way to extract information with swift 3.
This is what got so far
func getBookDetails() {
let scriptUrl = "https://www.googleapis.com/books/v1/volumes?q=isbn:9781451648546" .
let myurl = URL(string:scriptUrl)
let request = NSMutableURLRequest(url: myurl!)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: myurl! ) { (data, response, error) in
if error != nil{
print("THIS ERROR",error!)
return
} else{
if let mydata = data{
do{
let myJson = try (JSONSerialization.jsonObject(with: mydata, options: JSONSerialization.ReadingOptions.mutableContainers)) as AnyObject
// print("this is the MY JSON",myJson) ---> prints out the json
if let dictonary = myJson["items"] as AnyObject? {
print("the DICTONARY",dictonary) // ----> OUTPUT
if let dictonaryAA = dictonary["accessInfo"] as AnyObject? {
print("the accessInfo",dictonaryAA)
}
}
} catch{
print("this is the in CATCH")
}
} //data
}
}
task.resume()
}
}
OUTPUT :
the DICTONARY (
{
accessInfo = {
accessViewStatus = SAMPLE;
country = US;
=============
RELEVANT DATA as in https://www.googleapis.com/books/v1/volumes?
q=isbn:9781451648546"
==========================
title = "Steve Jobs";
};
}
)
Just need to parse through the json data to get the name, author and title of the book with reference to isbn.
Know there should be a better way to do things that is easily understandable to someone new into the language
You can parse the api in two ways
Using URLSession:
let rawDataStr: NSString = "data={\"mobile\":\"9420....6\",\"password\":\"56147180..1\",\"page_no\":\"1\"}"
self.parsePostAPIWithParam(apiName: "get_posts", paramStr: rawDataStr){ ResDictionary in
// let statusVal = ResDictionary["status"] as? String
self.postsDict = (ResDictionary["posts"] as! NSArray!) as! [Any]
print("\n posts count:",self.postsDict.count)
}
func parsePostAPIWithParam(apiName:NSString, paramStr:NSString,callback: #escaping ((NSDictionary) -> ())) {
var convertedJsonDictResponse:NSDictionary!
let dataStr: NSString = paramStr
let postData = NSMutableData(data: dataStr.data(using: String.Encoding.utf8.rawValue)!)
let request = NSMutableURLRequest(url: NSURL(string: "http://13.12..205.248/get_posts/")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = nil
request.httpBody = postData as Data
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error as Any)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse as Any)
do{
if let convertedJsonIntoDict = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
convertedJsonDictResponse = convertedJsonIntoDict.object(forKey: apiName) as? NSDictionary
// callback for response
callback(convertedJsonDictResponse)
}
} catch let error as NSError {
print(error)
}
}
Using Alamofire
func AlamofirePOSTRequest() {
let urlString = "http://13.12..205.../get_posts/"
let para = ["data": "{\"mobile\":\"9420....6\",\"password\":\"56147180..1\",\"page_no\":\"1\"}"]
Alamofire.request(urlString, method: .post, parameters: para , headers: nil).responseJSON {
response in
switch response.result {
case .success:
print("response: ",response)
let swiftyJsonVar = JSON(response.result.value!)
if let resData = swiftyJsonVar["posts"].arrayObject {
self.postsDict = resData as! [[String:AnyObject]]
}
print("\n \n alomafire swiftyJsonVar: ",swiftyJsonVar)
break
case .failure(let error):
print(error)
}
}
}
})
dataTask.resume()
}
First of all, all JSON types are value types in Swift 3 so the most unspecified type is Any, not AnyObject.
Second of all, there are only two collection types in the JSON type set, dictionary ([String:Any]) and array ([Any], but in most cases [[String:Any]]). It's never just Any nor AnyObject.
Third of all, the given JSON does not contain a key name.
For convenience let's use a type alias for a JSON dictionary:
typealias JSONDictionary = [String:Any]
The root object is a dictionary, in the dictionary there is an array of dictionaries for key items. And pass no options, .mutableContainers is nonsense in Swift.
guard let myJson = try JSONSerialization.jsonObject(with: mydata) as? JSONDictionary,
let items = myJson["items"] as? [JSONDictionary] else { return }
Iterate through the array and extract the values for title and authors which is an array by the way. Both values are in another dictionary for key volumeInfo.
for item in items {
if let volumeInfo = item["volumeInfo"] as? JSONDictionary {
let title = volumeInfo["title"] as? String
let authors = volumeInfo["authors"] as? [String]
print(title ?? "no title", authors ?? "no authors")
The ISBN information is in an array for key industryIdentifiers
if let industryIdentifiers = volumeInfo["industryIdentifiers"] as? [JSONDictionary] {
for identifier in industryIdentifiers {
let type = identifier["type"] as! String
let isbn = identifier["identifier"] as! String
print(type, isbn)
}
}
}
}
You are doing wrong in this line
if let dictonaryAA = dictonary["accessInfo"] as AnyObject?
because dictonary here is an array not dictionary. It is array of dictionaries. So as to get first object from that array first use dictonary[0], then use accessInfo key from this.
I am attaching the code for your do block
do{
let myJson = try (JSONSerialization.jsonObject(with: mydata, options: JSONSerialization.ReadingOptions.mutableContainers)) as AnyObject
// print("this is the MY JSON",myJson) ---> prints out the json
if let array = myJson["items"] as AnyObject? {
print("the array",array) // ----> OUTPUT
let dict = array.object(at: 0) as AnyObject//Master Json
let accessInf = dict.object(forKey: "accessInfo") //Your access info json
print("the accessInfo",accessInf)
}
}
Hope this helps you.
I am trying to load a values from a database and put them into a UITableView in the viewDidLoad function in one of my Swift files. When debugging, at the time of the view rendering, the list of values is empty, but after the view loads, the list gets populated by the view loads. I don't have much experience with threads in Swift, so I am not exactly sure why this is happening, any ideas? I have tried to run DispatchQueue.main.async, but that did not work My code is below:
override func viewDidLoad() {
super.viewDidLoad()
// Load any saved meals, otherwise load sample data.
loadDbMeals()
}
private func loadDbMeals() {
var dbMeals = [Meal]()
let requestURL = NSURL(string: self.URL_GET)
let request = NSMutableURLRequest(url: requestURL! as URL)
request.httpMethod = "GET"
//creating a task to send the post request
let task = URLSession.shared.dataTask(with: request as URLRequest){
data, response, error in
if error != nil{
print("error is \(String(describing: error))")
return;
}
//parsing the response
do {
//converting response to NSDictionary
let myJSON = try JSONSerialization.jsonObject(with: data!, options: [.mutableContainers]) as? NSDictionary
//parsing the json
if let parseJSON = myJSON {
if let nestedDictionary = parseJSON["message"] as? NSArray {
for meal in nestedDictionary {
if let nestedMeal = meal as? NSDictionary {
let mealName = nestedMeal["name"]
let rating = nestedMeal["rating"]
dbMeals.append(Meal(name: mealName as! String, photo: UIImage(named: "defaultPhoto"), rating: rating as! Int, ingredientList: [])!)
}
}
}
}
} catch {
print(error)
}
}
meals += dbMeals
//executing the task
task.resume()
}
So, the current order of breakpoints, is the call to loadDbMeals() in the viewDidLoad() function, then it tries to add the dbMeals variables to the global meals variable, and then the http request gets executed, after the empty list has already been added. I appreciate any help!
Reload your table after loading data
if let parseJSON = myJSON {
if let nestedDictionary = parseJSON["message"] as? NSArray {
for meal in nestedDictionary {
if let nestedMeal = meal as? NSDictionary {
let mealName = nestedMeal["name"]
let rating = nestedMeal["rating"]
dbMeals.append(Meal(name: mealName as! String, photo: UIImage(named: "defaultPhoto"), rating: rating as! Int, ingredientList: [])!)
}
}
DispatchQueue.main.async{
self.tableView.reloadData()
}
}
}
the request happens asynchronously. so the view is loaded while the request may still be in progress.
move the meals += dbMeals line into the request's completion handler (after the for loop), add a self. to the meals var since you are referencing it from within a closure and reload the tableview from the main thread afterwards:
DispatchQueue.main.async{
self.tableView.reloadData()
}
Because dataTask is not a synchronised call, we need to use lock to wait until all fetch is finished.
Code will look something like this:
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.global().async {
let lock = DispatchSemaphore(value: 0)
// Load any saved meals, otherwise load sample data.
self.loadDbMeals(completion: {
lock.signal()
})
lock.wait()
// finished fetching data
}
}
private func loadDbMeals(completion: (() -> Void)?) {
var dbMeals = [Meal]()
let requestURL = NSURL(string: self.URL_GET)
let request = NSMutableURLRequest(url: requestURL! as URL)
request.httpMethod = "GET"
//creating a task to send the post request
let task = URLSession.shared.dataTask(with: request as URLRequest){
data, response, error in
if error != nil{
print("error is \(String(describing: error))")
return;
}
//parsing the response
do {
//converting response to NSDictionary
let myJSON = try JSONSerialization.jsonObject(with: data!, options: [.mutableContainers]) as? NSDictionary
//parsing the json
if let parseJSON = myJSON {
if let nestedDictionary = parseJSON["message"] as? NSArray {
for meal in nestedDictionary {
if let nestedMeal = meal as? NSDictionary {
let mealName = nestedMeal["name"]
let rating = nestedMeal["rating"]
dbMeals.append(Meal(name: mealName as! String, photo: UIImage(named: "defaultPhoto"), rating: rating as! Int, ingredientList: [])!)
}
}
}
}
} catch {
print(error)
}
// call completion
completion()
}
meals += dbMeals
//executing the task
task.resume()
}
So execute loadDbMeals with completion block which will be called when fetching is finished and lock will wait until completion block is called.
I'm trying to pass data from a JSON response to a table view cell. I'm having problems with capturing the response values that I'm extracting in URLSession.shared.dataTask.
func callYouTubeAPIToGetAllVideos() {
let url = URL(string: "https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=XYZ&maxResults=50&order=date&key=ABC")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print(error!)
} else {
if let usableData = data {
let json = try? JSONSerialization.jsonObject(with: usableData, options: [])
if let dictionary = json as? [String: Any?] {
if let array = dictionary["items"] as? [Any] {
for object in array {
if let objectAsDictionary = object as? [String: Any?] {
if let objectWithKindAndVideoId = objectAsDictionary["id"] as? [String: String] {
if let videoId = objectWithKindAndVideoId["videoId"] {
//pass data to table cell
}
}
if let snippet = objectAsDictionary["snippet"] as? [String: Any] {
if let description = snippet["description"] {
//pass data to table cell
}
}
}
}
}
}
}
}
}
task.resume()
}
I tried appending the values to an instance variable but it didn't work.
Sorry about the messy code, this is my 1st time working with JSON in Swift.
First of all never declare a received JSON dictionary as [String:Any?]. A received dictionary value can't be nil.
Declare a custom struct Video.
struct Video {
let videoId : String
let description : String
}
Declare a data source array.
var videos = [Video]()
Parse the JSON into the array and reload the table view on the main thread.
func callYouTubeAPIToGetAllVideos() {
let url = URL(string: "https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=XYZ&maxResults=50&order=date&key=ABC")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print(error!)
} else {
do {
if let dictionary = try JSONSerialization.jsonObject(with: data!) as? [String: Any],
let array = dictionary["items"] as? [[String: Any]] {
for object in array {
if let objectWithKindAndVideoId = object["id"] as? [String: String],
let snippet = object["snippet"] as? [String: Any] {
let videoId = objectWithKindAndVideoId["videoId"] ?? ""
let description = snippet["description"] as? String ?? ""
let video = Video(videoId: videoId, description: description)
self.videos.append(video)
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
} catch {
print(error)
}
}
}
task.resume()
}
In cellForRow assign the values to the text properties
let video = videos[indexPath.row]
cell.textLabel!.text = video.videoId
cell.detailTextLabel?.text = video.description
I am trying to display some data I take from a data base into a TableView but the data is not shown in the TableView. The data I receive is formatted in JSON.
This is the data I receive form the data base and what I want to print in the TableViewis just David:
{"name":"David"}
This is the code to get the data from de data base:
let session = NSURLSession.sharedSession()
let request = NSURLRequest(URL: NSURL(string: "http://localhost:8888/Patients.php")!)
let task = session.dataTaskWithRequest(request) {data, response, downloadError in
if let error = downloadError {
print("Could not complete the request \(error)")
}
else {
do {
self.json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments)
} catch {
fatalError()
}
dispatch_async(dispatch_get_main_queue(), {
if let parseJSON = self.json{
let name = parseJSON["name"] as! String
self.arrayData.append(name)
print("Data1:\(self.arrayData)")
}
})
}
}
task.resume()
arrayData is an array where I put the data I receive from the data base and it is declared like this:
var arrayData: [String] = []
The code
print("Data1:\(self.arrayData)")
show in the console this Data1:["David"], so I get the data correctly.
Then I implement the methods to print in the ´TableView´, the numberOfSectionsInTableViewmethod, the numberOfRowsInSection method and the cellForRowAtIndexPath method but the data is not printed in the TableView.
I think the problem is that the TableViewis drawn before I put the data in the array so it prints nothing because the array is empty, and I don´t know how to fix it.
Anyone knows what is my problem?
yes, you're right.
session.dataTaskWithRequest
is async. Data is not returned immediately, it have delay.
You must to reload tableview after recieved data:
self.arrayData.append(name)
self.tableview.reloadData()
Usually i will use block:
func getData(handleComplete:((arr:NSMutableArray)->())){
let aray = NSMutableArray()
let session = NSURLSession.sharedSession()
let request = NSURLRequest(URL: NSURL(string: "http://localhost:8888/Patients.php")!)
let task = session.dataTaskWithRequest(request) {data, response, downloadError in
if let error = downloadError {
print("Could not complete the request \(error)")
}
else {
do {
self.json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments)
} catch {
fatalError()
}
dispatch_async(dispatch_get_main_queue(), {
if let parseJSON = self.json{
let name = parseJSON["name"] as! String
aray.append(name)
print("Data1:\(self.arrayData)")
}
handleComplete(aray)
})
}
}
task.resume()
arrayData
}
and in viewdidload i will call:
override func viewDidLoad() {
super.viewDidLoad()
self.getData { (arr) -> () in
self.tableview.reloadData()
}
}
it 's better