Click here to Skip to main content
15,880,967 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have Swift code to call on the Open Weather API.The code works well with any one word city (eg Rome), but balks at a city with more than one word (eg New York).

I have some print statements to show console output at various steps and they all work with a single word input city. The console output shows the expected JSON string.

With a city like New York or Los Angeles, I get the console print of the URL, but no JSON.

I copy and paste the NY console URL string into a browser and the site responds appropriately. Value of myKey redacted.

Output for Paris

URL is: https://api.openweathermap.org/data/2.5/weather?&appid=myKey&units=metric&q=Paris

JSON is:

\"weather\":[{\"id\":701,\"main\":\"Mist\",\"description\":\"mist\",\"icon\":\"50n\"}],\"base\":\"stations\",\"main\":{\"temp\":4.76,\"feels_like\":4.76,\"temp_min\":3.08,\"temp_max\":6.03,\"pressure\":1024,\"humidity\":92},\"visibility\":5000,\"wind\":{\"speed\":1.03,\"deg\":310},\"clouds\":{\"all\":90},\"dt\":1636571558,\"sys\":{\"type\":2,\"id\":2041230,\"country\":\"FR\",\"sunrise\":1636527115,\"sunset\":1636561035},\"timezone\":3600,\"id\":2988507,\"name\":\"Paris\",\"cod\":200}")

extracts of JSON:
CITY is Paris
TEMP IS 4.76
mist

for New York:
https://api.openweathermap.org/data/2.5/weather?&appid=myKey&units=metric&q=New York
No JSON

Any ideas?
Thanks!
Sleeper

What I have tried:

struct WeatherManager {

    

    let weatherURL =  "https://api.openweathermap.org/data/2.5/weather?&appid=myKey&units=metric"


    func fetchWeather (cityName:String) {

        let urlString = ("\(weatherURL)&q=\(cityName)")

        //let urlString = "https://api.openweathermap.org/data/2.5/weather?&appid=myKey&units=metric&q=New York"


        print("**URL*** \(urlString)")

        performRequest(urlString: urlString)

    }

    

    func performRequest(urlString: String) {

            //1.  create the URL? (optional)

        if let url = URL(string: urlString){

           // 2.  create URL Session- the thing that performs like a browser (default)

            let session = URLSession(configuration: .default)

           // 3.  give session a task;  task waits for data, so uses completion handler

           //     as a function()

            let task = session.dataTask(with: url, completionHandler: handle(data:response:error:))

           // 4.  start the task; "resume" because task is initialized as "suspended"

            task.resume()

        }

    }

    //function to "handle" input to completionHandler in #3; called by the task

    //passes data back to the completionHandler

    func handle(data: Data?, response: URLResponse?, error: Error? ) ->Void {

        //check for errors here

        if error != nil{

            print(error!)

            return  //exit failed

        }

            //optional binding of data

            if let safeData = data {

                //look at data in web data format utc8

                let dataString = String(data: safeData, encoding: .utf8)

                print(dataString)

                

                //new  cll func

                parseJSON(weatherData: safeData)

            }

        //new

        func parseJSON (weatherData: Data) {

           let decoder = JSONDecoder()

            //aski g for a type:  WeatherData is object, WeatherData.self is a type

            //since .decode can throw an error, use a DO  TRY CATCH

            do {

                //.decode creates a WeatherData.self object, so capture it in a constant

            let decodedData = try decoder.decode(WeatherData.self, from: weatherData)

                print("CITY is \(decodedData.name)")

                print(" TEMP IS \(decodedData.main.temp)")

                print("\(decodedData.weather[0].description)")

               

            } catch {

              print(error)

            }


    }

        

        }

    

}
Posted
Updated 11-Nov-21 7:01am
Comments
Richard Deeming 11-Nov-21 4:06am    
You probably need to URL-encode the city name before you inject it into the URL.
Sleeper 11888211 11-Nov-21 13:01pm    
Thanks Richard!

I added %20 to substitute for spaces:
New York ---> New%20York
and it worked as expected.

1 solution

Thanks Richard!

I added %20 to substitute for spaces:
New York ---> New%20York
and it worked as expected.

Swift:

if let city_old = searchTextField.text {
            city = city_old.replacingOccurrences(of: " ", with: "%20")
            weatherManager.fetchWeather(cityName: city)
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900