Implement a class with a swift protocol

0

I am trying to implement a class that should give me the weather, I am asked for a string as a parameter and also a completion and that is exactly where I get lost on how to implement it.

Try to call it using weatherDataWith to display the information in my UI but I do not succeed.

Here I leave the class to which I refer.

NOTE: This class can not and should not be modified.

I'm a bit of a novice in this, so excuse me if I'm not clear.

import UIKit
import Alamofire

typealias CityCompletion = (city:CityData) -> Void

struct ForecastData {
    var temperature:Int!
    var minimumTemperature:Float!
    var maximumTemperature:Float!
    var time:NSDate!
    var weatherDescription:String!
    var weatherCode:Int!
    var background:UIImage?
    var icon:UIImage!
}

struct CityData {
    var name:String?
    var countryISO:String?
    var forecasts:[ForecastData]!
}

enum WeatherUnits : String {
    case Metric = "&units=metric"
    case Imperial = "&units=imperial"
    case Standard = ""
}


class WeatherBase {
    static let sharedInstance = WeatherBase()
    var apiKey:String! = "b7507934ec3cef25f35b0f985ddb429c"
    var unit:WeatherUnits = .Metric

    private init() { }

    func iconWeather(code:Int) -> (icon:UIImage, background:UIImage) {
        switch code {
        case 200..<300:
            return (UIImage(named: "tormenta-icon")!, UIImage(named: "tormenta")!)
        case 300..<400:
            return (UIImage(named: "llovizna-icon")!, UIImage(named: "llovizna")!)
        case 500..<600:
            return (UIImage(named: "lluvia-icon")!, UIImage(named: "llovizna")!)
        case 600..<700:
            return (UIImage(named: "nieve-icon")!, UIImage(named: "nieve")!)
        case 700..<800:
            return (UIImage(named: "niebla-icon")!, UIImage(named: "niebla")!)
        case 800:
            return (UIImage(named: "soleado-icon")!, UIImage(named: "soleado")!)
        case 801..<810:
            return (UIImage(named: "nublado-icon")!, UIImage(named: "nublado")!)
        default:
            return (UIImage(named: "soleado-icon")!, UIImage(named: "soleado")!)
        }
    }

    func weatherDataWith(cityName:String, completion:CityCompletion) {
        let url = "http://api.openweathermap.org/data/2.5/forecast?q=\(cityName)&mode=json&appid=\(apiKey)\(unit.rawValue)&lang=es"
        let escapedAddress = url.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())

        Alamofire.request(.GET, escapedAddress!).responseJSON { (response) -> Void in
            if let result = response.result.value as? NSDictionary {
                var city = CityData()
                city.name = result["city"]!["name"] as? String
                city.countryISO = result["city"]!["country"] as? String

                var forecasts:[ForecastData] = []
                for f in result["list"] as! NSArray {
                    var forecast = ForecastData()
                    forecast.temperature = Int(round(f["main"]!!["temp"] as! Float))
                    forecast.maximumTemperature = (f["main"]!!["temp_max"] as! Float)
                    forecast.minimumTemperature = (f["main"]!!["temp_min"] as! Float)

                    forecast.time = NSDate(timeIntervalSince1970: (f["dt"] as! Double))

                    if let weather = f["weather"] as? NSArray {
                        print(weather)
                        forecast.weatherCode = weather[0]["id"] as! Int
                        forecast.weatherDescription = weather[0]["description"] as! String
                    }

                    let images = self.iconWeather(forecast.weatherCode)

                    forecast.icon = images.icon
                    forecast.background = images.background

                    forecasts.append(forecast)
                }

                city.forecasts = forecasts
                completion(city: city)
            }
        }
    }
}
    
asked by Heallz Slamer 25.08.2017 в 17:31
source

1 answer

1

I think your problem is this:

weatherDataWith(cityName: "Madrid") { (cityData) in
    DispatchQueue.main.async {
        //Aquí modificas la vista.
    }
}

The explanation for this is that the view runs in the main thread. When you make a call to a web service, which is what Alamofire does, you are opening a thread in the background and from that thread you can not modify the view. For that we use the DispatchQueue.main.async{} that code block runs asynchronously in the main thread .

If you have questions about concurrency I recommend you read how a multi-core processor works. It is an exciting world, but very difficult, both to understand and to manage.

    
answered by 16.10.2017 в 16:47