I'm setting up an API call to Tenor.com, docs here https://tenor.com/gifapi/documentation#responseobjects-gif .
I'm setting up a struct for my returning JSON, and I'm stuck on the media part.
For "media" it says to use "[ { GIF_FORMAT : MEDIA_OBJECT } ]".
How do I declare gif format and media objects? Or is there another way to set this up?
Here's what I've got do far.
struct structForAllApiResults: Codable {
// MARK: - Gif Object
let created: Float // a unix timestamp representing when this post was created.
let hasaudio: Bool // true if this post contains audio (only video formats support audio, the gif image file format can not contain audio information).
let id: String //Tenor result identifier
let media: [ Dictionary<GIF,>] // An array of dictionaries with GIF_FORMAT as the key and MEDIA_OBJECT as the value
let tags: [String] // an array of tags for the post
let title: String // the title of the post.
let itemurl: String // the full URL to view the post on tenor.com.
let hascaption: Bool // true if this post contains captions
let url: String // a short URL to view the post on tenor.com.
// MARK: - Category Object
let searchterm: String
let path: String
let image: String
let name: String
// MARK: - Media Object
let preview: String
let url: String
let dims: [Int] // dimensions
// MARK: - Format Types
let gif:
}
Post
Replies
Boosts
Views
Activity
I have a large JSON file with a top level array:
[
{
"tag" : "AF",
"geopoliticalarea" : "Afghanistan",
"travel_transportation" :
etc...
}
]
The JSON file is a list of every country along with info for each country. You can see it here if you'd like:
https://cadatacatalog.state.gov/dataset/4a387c35-29cb-4902-b91d-3da0dc02e4b2/resource/299b3b67-3c09-46a3-9eb7-9d0086581bcb/download/countrytravelinfo.json
I've set up a struct for the JSON info:
struct ReceivedAPIData: Codable {
let tag: String
let geopoliticalarea: String
let travel_transportation: String // with html
let health: String // with html
let destination_description: String // with html
let iso_code: String
let travel_embassyAndConsulate: String // with html
let last_update_date: String
}
(Initially I wanted to use an API call but if it's easier to save all of the data locally I'm not opposed to that).
What I'm having trouble with is identifying/grouping/and pulling out all the the above info for one country at a time.
The entire file is in an array but I don't know how to access each country. If I look at the link with Firefox I can see that each country is assigned a number, 0 - 210, but maybe that's just Firefox helping out? I don't see any numbers like that in the raw JSON.
Here's my API call func:
guard let apiUrl = URL(string: "https://cadatacatalog.state.gov/dataset/4a387c35-29cb-4902-b91d-3da0dc02e4b2/resource/299b3b67-3c09-46a3-9eb7-9d0086581bcb/download/countrytravelinfo.json")
else {
print("Error: cannot create URL.")
return
}
let session = URLSession(configuration: .default)
let task = session.dataTask(with: apiUrl) { [self] data, response, error in
let decoder = JSONDecoder()
guard let safeData = data else {
print("Couldn't get data back from url.");
return
}
guard let safeDecodeData = try? decoder.decode([ReceivedAPIData].self, from: safeData) else {
fatalError("Couldn't decode data.")}
self.delegate?.didUpdateAPIResults(returnedResult: safeDecodeData)
let jsonStringData = data?.prettyPrintedJSONString
print("Pretty JSON from server ----- \(String(describing: jsonStringData))")
// Use this to remove the HTML from the string data later safeDecodeData.map -> { ReceivedAPIData in
//
// }
if let e = error {
print(e.localizedDescription)
}
callCompletionHandler(safeDecodeData)
}
task.resume()
}
}
My goal for this app is to search by country name in a text field and have only the info for that county displayed.
I've googled around about top level arrays and nested JSON info but can't figure out what my next step is.
Thanks.
I want to get data from the State Department about different countries.
I'm using https://cadatacatalog.state.gov/dataset/travel/resource/299b3b67-3c09-46a3-9eb7-9d0086581bcb as a template to build my struct for the API call.
Some items are obvious string types which aren't a problem, but others have HTML code in them.
"geopoliticalarea": "Afghanistan",
"travel_transportation": "<div style=\"margin-top:5px\"> <p><p><b>Traffic Safety and Road Conditions:</b>
How can I get the text from these objects without the HTML coding and tags?
I've searched and haven't found anything that would work.
I'm using the Openweathermap API to make calls and I'm building my app to display the results in a tableview, with the 4 results per call displayed in one tableview cell, each with their own label.
The struct I have set up for the results that I want is
struct MappedResult {
var locationName: String
var temperatureInF: Double
var longitude: Float
var latitude: Float
}
I initialize this struct in my ViewController as
var myResult: MappedResult = MappedResult(
locationName: "String",
temperatureInF: 0,
longitude: 0,
latitude: 0
)
var myTableViewData: [MappedResult] = []
and further down in the VC, in my tableView func I have
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let rowPosition: Int = indexPath.item
let myApiResultItem: MappedResult = myTableViewData[rowPosition]
let dequeuedCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: C.cellIdentifier, for: indexPath)
let weatherCell = dequeuedCell as! MyWeatherTableViewCell
weatherCell.connectLabels(
loc: myApiResultItem.locationName,
temp: myApiResultItem.temperatureInF,
lat: myApiResultItem.latitude,
long: myApiResultItem.longitude)
weatherCell.backgroundColor = .systemGray
return weatherCell
}
I have a separate class set up for the labels, and this is where I'm having trouble. I can't figure out how to convert the floats and double to string types so their data can be displayed in their labels.
I've tried Googling about how to change the types, I've searched the error, I've tried type casting (don't know much about it), declaring them as you see them now, and I came across a NumberFormatter func but don't know if that's the right thing to use, or even how to implement it.
class MyWeatherTableViewCell: UITableViewCell {
@IBOutlet weak var locationLabel: UILabel!
@IBOutlet weak var tempInFLabel: UILabel!
@IBOutlet weak var longLabel: UILabel!
@IBOutlet weak var latLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func connectLabels(loc: String, temp: Double, lat: Float, long: Float) {
locationLabel.text = loc
Double(tempInFLabel.text!) = temp **
Float(latLabel.text!) = lat **
Float(longLabel.text!) = long **
}
}
The last three labels with the ** have the error
Expression is not assignable: function call returns immutable value.
How do I fix this? Thanks.
Hi, I'm new to programming and am working on an app based originally on Angela Yu's Clima app. I have my functions set up for the API call and am stuck on the escaping closures and passing in the correct arguments for them.
MappedResults is a separate struct that I set up for the relevant API data that I want to capture.
I think my confusion is around the myResults and MappedResults() but I'm not 100% on that.
(Once I figure this out, my next step will be to take that passed info and populate it into a tableview, which is why I'm using escaping closures).
import UIKit
import CoreLocation
protocol APIManagerDelegate {
func didUpdateAPIResults(inputMyResults: MappedResults)
func didFailWithError(error: Error)
}
class APIManager {
var myResults = MappedResults(
locationName: "String",
temperatureInF: 0,
longitude: 0,
latitude: 0
)
let dataURL = ""
let myApiKey = ""
var delegate: APIManagerDelegate?
func fetchData(location: String, fetchDataCompletionHandler: @escaping (MappedResults) - Void) {
var urlComponents = URLComponents(string: dataURL)
urlComponents?.queryItems = [
URLQueryItem(name: "appId", value: myApiKey),
URLQueryItem(name: "units", value: "imperial"),
URLQueryItem(name: "q", value: location),
]
self.performRequest(url: urlComponents?.url, performRequestCompletionHandler: {_ in
fetchDataCompletionHandler(self.myResults)
})
}
func performRequest(url: URL?, performRequestCompletionHandler: @escaping (MappedResults) - Void) {
guard let url = url else {print("Cannot Return URL Safely") ; return}
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { data, response, error in
guard let data = data else {print("Couldn't get back data from url task") ; return}
guard let MappedResults = self.parseJSON(rawJsonData: data) else {print("Couldn't get mapped results") ; return}
self.delegate?.didUpdateAPIResults(inputMyResults: MappedResults)
if let e = error {
print(e.localizedDescription)
}
performRequestCompletionHandler(MappedResults)
}
task.resume()
}
func parseJSON(rawJsonData: Data) - MappedResults? {
let decoder = JSONDecoder()
do {
let decodedAPIResults: APIResults =
try decoder.decode(
APIResults.self,
from: rawJsonData)
let myResults = MappedResults(
locationName: decodedAPIResults.name,
temperatureInF: decodedAPIResults.main.temp,
longitude: decodedAPIResults.coord.lon,
latitude: decodedAPIResults.coord.lat
)
return myResults
} catch {
delegate?.didFailWithError(error: error)
return nil
}
}
}
Thanks
I'm working on a weather app where I type in the name of the city in the text field, the app then hits the Open Weather Map API, and returns the weather for that location. It works if the city name is only one word, like Chicago, but a city with two words in it, such as Los Angeles, doesn't work.
I'm new to programming and my understanding is that to indicate a space in a URL, the space needs to be represented as "%20".
Checking it in my browser, adding "&q=Los%20Angeles" to the end of the URL works.
What's the best way to incorporate the possibility of a space being entered in a name in the text field, and then formatting that string w/a space into a URL?
import UIKit
import CoreLocation
protocol APIManagerDelegate {
func didUpdateData(_ APIManager: APIManager, data: APIManager)
func didFailWithError(error: Error)
}
struct APIManager {
let dataURL = "https://api.openweathermap.org/data/2.5/weather?appid=MyAPIID&units=imperial"
var delegate: APIManagerDelegate?
func fetchData(location: String) {
let urlString = "\(dataURL)&q=\(location)"
performRequest(urlString: urlString)
/*print(urlString)*/
}
func performRequest(urlString: String) {
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!)
return
}
if let safeData = data {
self.parseJSON(cityData: safeData)
}
}
task.resume()
}
}
func parseJSON(cityData: Data) {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(APIResults.self, from: cityData)
/*print(decodedData.name.name)*/
print(decodedData.main.temp)
print(decodedData.coord.lat)
print(decodedData.coord.lon)
} catch {
print(error)
}
}
}