我的标签应用程序崩溃了,我真的无法找到解决方案。当应用程序第一次执行时,当我选择第三个选项卡项(天气预报)时,一切正常,表数据加载其中的所有数据,一切正常显示,用户可以毫无问题地进行交互。当我选择另一个标签项然后返回到天气预报项时,会发生崩溃问题。我担心的是,它有时会崩溃,但有时它不会......这是我真正无法理解的,为什么它连续几次都会工作一次,有时它会在第一次尝试时崩溃。我想在某些情况下在viewdidAppear加载时指向视图生命周期,我的数组没有及时填充,因此TableView正在尝试访问不存在和崩溃的数组元素。这是我尝试使用线程和dispatchQueue进行管理但仍然出现问题..
有什么想法吗?非常感谢你的帮助。
有时我收到此错误消息:
2017-12-09 14:19:11.431048 + 0100 Le Baluchon [19344:5162393] ***因未捕获的异常终止应用程序' NSInternalInconsistencyException',原因:'无效更新:无效第0节中的行数。更新后的现有部分中包含的行数(0)必须等于更新前该部分中包含的行数(4),加上或减去插入的行数或从该部分删除(插入0,删除0)并加上或减去移入或移出该部分的行数(0移入,0移出)
但很多时候,我在VC的第73行旁边收到此错误消息:
线程1:致命错误:索引超出范围
有什么想法吗?
这是我的VIewController:
class WeatherViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet weak var weatherView: UITableView!
@IBOutlet weak var weatherDataLoading: UIActivityIndicatorView!
let error = Notification.Name(rawValue: "Error")
var selectedRow: Int?
var count: Int = 0
var names = [String]()
var temps = [String]()
var dates = [String]()
var climates = [String]()
var forecastDates = [String]()
var forecastClimates = [String]()
override func viewDidLoad() {
super.viewDidLoad()
self.weatherView.dataSource = self
self.weatherView.delegate = self
NotificationCenter.default.addObserver(self, selector: #selector(displayErrorAlert), name: error, object: nil)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
WeatherRequest.getWeatherCast(completion: { (names, temps, dates, climates, forecastdates, forecastclimates) in
self.names = names
self.temps = temps
self.dates = dates
self.climates = climates
self.forecastDates = forecastdates
self.forecastClimates = forecastclimates
self.weatherView.reloadData()
self.weatherDataLoading.isHidden = true
})
}
@objc func displayErrorAlert() {
let alertVC = UIAlertController(title: "Error", message: "Couldn't retrieve data from servor", preferredStyle: .alert)
alertVC.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alertVC, animated: true, completion: nil)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "table_cell", for: indexPath) as! WeatherViewCell
cell.separatorInset = UIEdgeInsets.zero
cell.firstStackView.constant = tableView.frame.height / 4
cell.cityName.text = names[indexPath.item]
cell.cityDate.text = dates[indexPath.item]
cell.cityClimate.text = climates[indexPath.item]
cell.cityTemp.text = temps[indexPath.item]
cell.firstForecastedClimate.text = forecastClimates[count]
cell.firstForecastedDate.text = forecastDates[count]
count += 1
cell.secondForecastedClimate.text = forecastClimates[count]
cell.secondForecastedDate.text = forecastDates[count]
count += 1
cell.thirdForecastedClimate.text = forecastClimates[count]
cell.thirdForecastedDate.text = forecastDates[count]
cell.isExpanded = false
count += 8
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? WeatherViewCell
else { return }
selectedRow = indexPath.item
cell.contentView.backgroundColor = UIColor.darkGray
cell.contentView.alpha = 0.5
cell.isExpanded = !cell.isExpanded
self.weatherView.beginUpdates()
self.weatherView.endUpdates()
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? WeatherViewCell
else { return }
self.weatherView.beginUpdates()
cell.contentView.backgroundColor = nil
cell.contentView.alpha = 1
cell.isExpanded = false
self.weatherView.endUpdates()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
guard let selectedRow = selectedRow else { return }
guard let cell = weatherView.cellForRow(at: [0,selectedRow]) as? WeatherViewCell
else { return }
cell.isExpanded = false
weatherView.beginUpdates()
cell.contentView.backgroundColor = nil
cell.contentView.alpha = 1
weatherView.endUpdates()
clear()
}
func clear() {
count = 0
names = [String]()
temps = [String]()
dates = [String]()
climates = [String]()
forecastDates = [String]()
forecastClimates = [String]()
}
}
这是我从API Yahoo Weather获取数据的类。
class WeatherRequest {
static func getWeatherCast(completion: @escaping ([String], [String], [String], [String], [String], [String]) -> ()) {
DispatchQueue.global(qos: .userInteractive).async {
var names = [String]()
var temps = [String]()
var dates = [String]()
var climates = [String]()
var forecastDates = [String]()
var forecastClimates = [String]()
let url = URL(string: "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%20in(%22Miami%22%2C%20%22new%20york%22%2C%20%22chicago%22%2C%20%22philadelphia%22))%20and%20u%3D'c'&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
guard let myData = data else { return }
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let root = try decoder.decode(Root.self, from: myData)
for channel in root.channels {
dates.append(channel.item.condition.date)
temps.append(channel.item.condition.temp + " °C")
climates.append(channel.item.condition.text)
}
for channel in root.channels {
for forecast in channel.item.forecast {
forecastDates.append(forecast.date)
forecastClimates.append(forecast.text)
}
}
names = ["Miami", "New York", "Chicago", "Philadelphia"]
DispatchQueue.main.async {
completion(names, temps, dates, climates, forecastDates, forecastClimates)
}
} catch let fetchError {
print(fetchError)
}
}
task.resume()
}
}
}