[ad_1]
I am engaged on climate tracker and need to show some information in my ViewController, however I do not perceive why some worth from my view mannequin is on closure, however not displayed in my assortment view
JSON
{
"cod": "200",
"message": 0,
"cnt": 3,
"listing": [
{
"dt": 1638370800,
"main": {
"temp": 282.21,
"feels_like": 279.54,
"temp_min": 281.53,
"temp_max": 282.21,
"pressure": 998,
"sea_level": 998,
"grnd_level": 995,
"humidity": 71,
"temp_kf": 0.68
},
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10d"
}
],
"clouds": {
"all": 79
},
"wind": {
"velocity": 5.05,
"deg": 288,
"gust": 10.52
},
"visibility": 10000,
"pop": 0.48,
"rain": {
"3h": 0.21
},
"sys": {
"pod": "d"
},
"dt_txt": "2021-12-01 15:00:00"
},
{
"dt": 1638381600,
"major": {
"temp": 280.71,
"feels_like": 277.76,
"temp_min": 279.79,
"temp_max": 280.71,
"stress": 1000,
"sea_level": 1000,
"grnd_level": 998,
"humidity": 76,
"temp_kf": 0.92
},
"climate": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10n"
}
],
"clouds": {
"all": 87
},
"wind": {
"velocity": 4.84,
"deg": 20,
"gust": 10.28
},
"visibility": 10000,
"pop": 0.88,
"rain": {
"3h": 1.15
},
"sys": {
"pod": "n"
},
"dt_txt": "2021-12-01 18:00:00"
},
{
"dt": 1638392400,
"major": {
"temp": 278.21,
"feels_like": 274.28,
"temp_min": 278.21,
"temp_max": 278.21,
"stress": 1005,
"sea_level": 1005,
"grnd_level": 1002,
"humidity": 72,
"temp_kf": 0
},
"climate": [
{
"id": 803,
"main": "Clouds",
"description": "broken clouds",
"icon": "04n"
}
],
"clouds": {
"all": 73
},
"wind": {
"velocity": 5.62,
"deg": 345,
"gust": 10.72
},
"visibility": 10000,
"pop": 0.39,
"sys": {
"pod": "n"
},
"dt_txt": "2021-12-01 21:00:00"
}
],
"metropolis": {
"id": 2643743,
"identify": "London",
"coord": {
"lat": 51.5085,
"lon": -0.1257
},
"nation": "GB",
"inhabitants": 1000000,
"timezone": 0,
"dawn": 1638344651,
"sundown": 1638374122
}
}
My struct
struct TwentyFourHoursCitiesWeather: Decodable {
let cod: String
let message, cnt: Int
let listing: [List]
let metropolis: Metropolis
}
// MARK: - Metropolis
struct Metropolis: Decodable {
let id: Int
let identify: String
let coord: Coord
let nation: String
let inhabitants, timezone, dawn, sundown: Int
}
// MARK: - Coord
struct Coord: Decodable {
let lat, lon: Double
}
// MARK: - Listing
struct Listing: Decodable {
let dt: Int
let major: TwentyFourHoursMain
let climate: [TwentyFourHoursWeather]
let clouds: TwentyFourHoursClouds
let wind: TwentyFourHoursWind
let visibility: Int
let pop: Double
let rain: Rain?
let sys: TwentyFourHoursSys
let dtTxt: String
enum CodingKeys: String, CodingKey {
case dt, major, climate, clouds, wind, visibility, pop, rain, sys
case dtTxt = "dt_txt"
}
}
// MARK: - Clouds
struct TwentyFourHoursClouds: Decodable {
let all: Int
}
// MARK: - Major
struct TwentyFourHoursMain: Decodable {
let temp, feelsLike, tempMin, tempMax: Double
let stress, seaLevel, grndLevel, humidity: Int
let tempKf: Double
enum CodingKeys: String, CodingKey {
case temp
case feelsLike = "feels_like"
case tempMin = "temp_min"
case tempMax = "temp_max"
case stress
case seaLevel = "sea_level"
case grndLevel = "grnd_level"
case humidity
case tempKf = "temp_kf"
}
}
// MARK: - Rain
struct Rain: Decodable {
let the3H: Double
enum CodingKeys: String, CodingKey {
case the3H = "3h"
}
}
// MARK: - Sys
struct TwentyFourHoursSys: Decodable {
let pod: String
}
// MARK: - Climate
struct TwentyFourHoursWeather: Decodable {
let id: Int
let major, weatherDescription, icon: String
enum CodingKeys: String, CodingKey {
case id, major
case weatherDescription = "description"
case icon
}
}
// MARK: - Wind
struct TwentyFourHoursWind: Decodable {
let velocity: Double
let deg: Int
let gust: Double
}
My WeatherService, once I get information:
protocol ITwentyFourHoursWeatherService {
func getCitiesWeather(completion: @escaping (Outcome<TwentyFourHoursCitiesWeather, Error>) -> Void)
}
enum TwentyFourHoursWeatherServiceError: Error {
case badUrl
}
non-public extension String {
static let url = "https://api.openweathermap.org/information/2.5/forecast?q=London&cnt=3&appid=KEY"
}
remaining class TwentyFourHoursWeatherService: ITwentyFourHoursWeatherService {
func getCitiesWeather(completion: @escaping (Outcome<TwentyFourHoursCitiesWeather, Error>) -> Void) {
guard let url = URL(string: .url) else {
return completion(.failure(TwentyFourHoursWeatherServiceError.badUrl))
}
let process = URLSession.shared.dataTask(with: url) { information, response, error in
guard let information = information, error == nil else { return }
do {
let outcome = attempt JSONDecoder().decode(TwentyFourHoursCitiesWeather.self, from: information)
completion(.success(outcome))
print("24 weatherService: (outcome.listing[0].major.temp)") <--I get information right here
} catch {
print("did not convert (error)")
}
}
process.resume()
}
}
My ViewModel:
class TwentyFourHoursViewModel {
// MARK: -Properties
let twentyFourHoursWeatherService: ITwentyFourHoursWeatherService
var twentyFourHoursWeather: TwentyFourHoursMainScreenWeatherModel?
init(twentyFourHoursWeatherService: ITwentyFourHoursWeatherService) {
self.twentyFourHoursWeatherService = twentyFourHoursWeatherService
}
func twentyFourHoursViewDidLoad() {
twentyFourHoursWeatherService.getCitiesWeather { [weak self] end in
swap outcome {
case .success(let outcome):
self?.twentyFourHoursWeather = .init(
twentyFourHoursTime: outcome.listing[2].dtTxt ,
twentyFourHoursIcon: "sundown",
twentyFourHoursTemp: outcome.listing[1].major.temp
)
self?.twentyFourHoursWeatherDidChange?()
print("In twentyFourHoursViewModel: (outcome.listing[0].major.temp)") <-- Get information right here
case .failure(let error):
print(error.localizedDescription)
}
}
}
var twentyFourHoursWeatherDidChange: (() -> Void)?
My ViewController:
class MainScrenenViewController: UIViewController {
let twentyFourHoursViewModel: TwentyFourHoursViewModel
//CollectionView
var todayCollectionView: UICollectionView = {
let structure = UICollectionViewFlowLayout()
structure.scrollDirection = .horizontal
let todayCollectionView = UICollectionView(body: .zero, collectionViewLayout: structure)
todayCollectionView.register(TwentyFourHoursCollectionViewCell.self, forCellWithReuseIdentifier: "todayCell")
todayCollectionView.translatesAutoresizingMaskIntoConstraints = false
todayCollectionView.backgroundColor = .white
return todayCollectionView
}()
//MARK: - Initialization
init(twentyFourHoursViewModel: TwentyFourHoursViewModel) {
self.twentyFourHoursViewModel = twentyFourHoursViewModel
tremendous.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been applied")
}
//MARK: - Lifecycle
override func viewDidLoad() {
tremendous.viewDidLoad()
view.backgroundColor = .white
view.addSubview(todayCollectionView)
todayCollectionView.dataSource = self
todayCollectionView.delegate = self
setupConstraints()
twentyFourHoursViewModel.twentyFourHoursWeatherDidChange = {
DispatchQueue.major.async {
self.collectionView.reloadData()
print("Значение из замыкания: (self.twentyFourHoursViewModel.twentyFourHoursWeather?.twentyFourHoursTemp)") <--And I get information right here
}
}
twentyFourHoursViewModel.twentyFourHoursViewDidLoad()
}
//MARK: - Assortment
extension MainScrenenViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection part: Int) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cellTwo = collectionView.dequeueReusableCell(withReuseIdentifier: "todayCell", for: indexPath) as! TwentyFourHoursCollectionViewCell
if let temp: String? = String(twentyFourHoursViewModel.twentyFourHoursWeather?.twentyFourHoursTemp ?? 1.1) {
cellTwo.mainTemperatureLabel.textual content = temp
print("Значение в ячейке: (temp)") <-- There's nil right here
}
return cellTwo
}
Assortment View Cell
class TwentyFourHoursCollectionViewCell: UICollectionViewCell {
var mainTemperatureLabel: UILabel = {
let label = UILabel()
label.font = UIFont(identify: "Rubik-Medium", dimension: 16)
label.textColor = .black
label.textAlignment = .heart
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override init(body: CGRect) {
tremendous.init(body: body)
contentView.addSubview(mainTemperatureLabel)
//self.contentView.layer.cornerRadius = 10
let constraints = [
mainTemperatureLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
mainTemperatureLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
mainTemperatureLabel.heightAnchor.constraint(equalToConstant: 30),
mainTemperatureLabel.widthAnchor.constraint(equalToConstant: 30),
]
NSLayoutConstraint.activate(constraints)
}
required init?( coder: NSCoder) {
fatalError("init(coder:) has not been applied")
}
}
[ad_2]
