【发布时间】:2022-01-09 22:41:29
【问题描述】:
我正在开发天气跟踪器,想在我的 ViewController 中显示一些数据,但我不明白为什么我的视图模型中的某些值正在关闭,但没有显示在我的集合视图中
JSON
{
"cod": "200",
"message": 0,
"cnt": 3,
"list": [
{
"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": {
"speed": 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,
"main": {
"temp": 280.71,
"feels_like": 277.76,
"temp_min": 279.79,
"temp_max": 280.71,
"pressure": 1000,
"sea_level": 1000,
"grnd_level": 998,
"humidity": 76,
"temp_kf": 0.92
},
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10n"
}
],
"clouds": {
"all": 87
},
"wind": {
"speed": 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,
"main": {
"temp": 278.21,
"feels_like": 274.28,
"temp_min": 278.21,
"temp_max": 278.21,
"pressure": 1005,
"sea_level": 1005,
"grnd_level": 1002,
"humidity": 72,
"temp_kf": 0
},
"weather": [
{
"id": 803,
"main": "Clouds",
"description": "broken clouds",
"icon": "04n"
}
],
"clouds": {
"all": 73
},
"wind": {
"speed": 5.62,
"deg": 345,
"gust": 10.72
},
"visibility": 10000,
"pop": 0.39,
"sys": {
"pod": "n"
},
"dt_txt": "2021-12-01 21:00:00"
}
],
"city": {
"id": 2643743,
"name": "London",
"coord": {
"lat": 51.5085,
"lon": -0.1257
},
"country": "GB",
"population": 1000000,
"timezone": 0,
"sunrise": 1638344651,
"sunset": 1638374122
}
}
我的结构
struct TwentyFourHoursCitiesWeather: Decodable {
let cod: String
let message, cnt: Int
let list: [List]
let city: City
}
// MARK: - City
struct City: Decodable {
let id: Int
let name: String
let coord: Coord
let country: String
let population, timezone, sunrise, sunset: Int
}
// MARK: - Coord
struct Coord: Decodable {
let lat, lon: Double
}
// MARK: - List
struct List: Decodable {
let dt: Int
let main: TwentyFourHoursMain
let weather: [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, main, weather, clouds, wind, visibility, pop, rain, sys
case dtTxt = "dt_txt"
}
}
// MARK: - Clouds
struct TwentyFourHoursClouds: Decodable {
let all: Int
}
// MARK: - Main
struct TwentyFourHoursMain: Decodable {
let temp, feelsLike, tempMin, tempMax: Double
let pressure, 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 pressure
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: - Weather
struct TwentyFourHoursWeather: Decodable {
let id: Int
let main, weatherDescription, icon: String
enum CodingKeys: String, CodingKey {
case id, main
case weatherDescription = "description"
case icon
}
}
// MARK: - Wind
struct TwentyFourHoursWind: Decodable {
let speed: Double
let deg: Int
let gust: Double
}
我的 WeatherService,当我获取数据时:
protocol ITwentyFourHoursWeatherService {
func getCitiesWeather(completion: @escaping (Result<TwentyFourHoursCitiesWeather, Error>) -> Void)
}
enum TwentyFourHoursWeatherServiceError: Error {
case badUrl
}
private extension String {
static let url = "https://api.openweathermap.org/data/2.5/forecast?q=London&cnt=3&appid=KEY"
}
final class TwentyFourHoursWeatherService: ITwentyFourHoursWeatherService {
func getCitiesWeather(completion: @escaping (Result<TwentyFourHoursCitiesWeather, Error>) -> Void) {
guard let url = URL(string: .url) else {
return completion(.failure(TwentyFourHoursWeatherServiceError.badUrl))
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else { return }
do {
let result = try JSONDecoder().decode(TwentyFourHoursCitiesWeather.self, from: data)
completion(.success(result))
print("24 weatherService: \(result.list[0].main.temp)") <--I get data here
} catch {
print("failed to convert \(error)")
}
}
task.resume()
}
}
我的 ViewModel:
类 TwentyFourHoursViewModel {
// MARK: -Properties
let twentyFourHoursWeatherService: ITwentyFourHoursWeatherService
var twentyFourHoursWeather: TwentyFourHoursMainScreenWeatherModel?
init(twentyFourHoursWeatherService: ITwentyFourHoursWeatherService) {
self.twentyFourHoursWeatherService = twentyFourHoursWeatherService
}
func twentyFourHoursViewDidLoad() {
twentyFourHoursWeatherService.getCitiesWeather { [weak self] result in
switch result {
case .success(let result):
self?.twentyFourHoursWeather = .init(
twentyFourHoursTime: result.list[2].dtTxt ,
twentyFourHoursIcon: "sunset",
twentyFourHoursTemp: result.list[1].main.temp
)
self?.twentyFourHoursWeatherDidChange?()
print("In twentyFourHoursViewModel: \(result.list[0].main.temp)") <-- Get data here
case .failure(let error):
print(error.localizedDescription)
}
}
}
var twentyFourHoursWeatherDidChange: (() -> Void)?
我的视图控制器:
class MainScrenenViewController: UIViewController {
let twentyFourHoursViewModel: TwentyFourHoursViewModel
//CollectionView
var todayCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let todayCollectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
todayCollectionView.register(TwentyFourHoursCollectionViewCell.self, forCellWithReuseIdentifier: "todayCell")
todayCollectionView.translatesAutoresizingMaskIntoConstraints = false
todayCollectionView.backgroundColor = .white
return todayCollectionView
}()
//MARK: - Initialization
init(twentyFourHoursViewModel: TwentyFourHoursViewModel) {
self.twentyFourHoursViewModel = twentyFourHoursViewModel
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(todayCollectionView)
todayCollectionView.dataSource = self
todayCollectionView.delegate = self
setupConstraints()
twentyFourHoursViewModel.twentyFourHoursWeatherDidChange = {
DispatchQueue.main.async {
self.collectionView.reloadData()
print("Значение из замыкания: \(self.twentyFourHoursViewModel.twentyFourHoursWeather?.twentyFourHoursTemp)") <--And I get data here
}
}
twentyFourHoursViewModel.twentyFourHoursViewDidLoad()
}
//MARK: - Collection
extension MainScrenenViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: 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.text = temp
print("Значение в ячейке: \(temp)") <-- There is nil here
}
return cellTwo
}
集合视图单元格
class TwentyFourHoursCollectionViewCell: UICollectionViewCell {
var mainTemperatureLabel: UILabel = {
let label = UILabel()
label.font = UIFont(name: "Rubik-Medium", size: 16)
label.textColor = .black
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
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 implemented")
}
}
【问题讨论】:
-
您将
result.list[1].main.temp分配给temp,但在其他任何地方您都使用索引0 -
将此
if let temp: String? =更改为if let temp: String =甚至if let temp =。 if let 返回一个可选项没有多大意义。此时您需要一个实际值。还可以尝试将那个长的可选链分解为离散的中间值,看看发生了什么。设置断点。使用非常强大的 Xcode 调试器来单步调试您的代码。请注意,当您首次显示集合视图时,您希望获得nil,然后在重新加载时获得一个值 -
@Paulw11 写入
if let temp =时出现错误条件绑定的初始化程序必须具有可选类型,而不是“字符串” -
@Paulw11 抱歉,我不明白这条评论:您将 result.list[1].main.temp 分配给 temp,但在其他任何地方都使用索引 0
-
您在
.success的情况下说twentyFourHoursTemp: result.list[1].main.temp,但在您的日志中使用list[0]
标签: ios json swift xcode collectionview