我解析JSON文件,而不是在Core Data托管上下文中创建新对象。此时一切正常,我得到了所有有效的对象。但是当我尝试使用NSFetchedResultsControllerDelegate方法在tableView上更新数据时出现问题 - NSFetchedResultsController为2个不同的索引路径返回相同的对象。而且,如果我尝试用断点来捕获问题,那么3次NSFetchedResultsController开始返回有效对象。这是Core Data的错误还是其他? 的修改 解析JSON并保存到核心数据:
private func performRequest(withURL url: URL) {
Alamofire.request(url).responseJSON(completionHandler: { (response) in
guard let result = response.result.value as? [String: Any] else {
return
}
DispatchQueue.main.async {
self.deleteAllPreviousData()
self.processResponse(result)
self.coreDataStack.saveContext()
}
})
}
private func deleteAllPreviousData() {
let fetchCity = NSFetchRequest<NSFetchRequestResult>(entityName: "City")
let fetchWeather = NSFetchRequest<NSFetchRequestResult>(entityName: "Weather")
let requestCityDelete = NSBatchDeleteRequest(fetchRequest: fetchCity)
requestCityDelete.affectedStores = coreDataStack.managedContext.persistentStoreCoordinator?.persistentStores
let requestWeatherDelete = NSBatchDeleteRequest(fetchRequest: fetchWeather)
requestWeatherDelete.affectedStores = coreDataStack.managedContext.persistentStoreCoordinator?.persistentStores
do {
try coreDataStack.managedContext.execute(requestWeatherDelete)
try coreDataStack.managedContext.execute(requestCityDelete)
} catch let error as NSError {
print("Delete fetching error: \(error), \(error.userInfo)")
}
}
private func processResponse(_ dictionary: [String: Any]) {
guard let cityList = dictionary["list"] as? [Any] else {
return
}
let newUpdateDate = Date()
for (id, city) in cityList.enumerated() {
//parse data from JSON
guard let city = city as? [String: Any] else {
return
}
let name = city["name"] as? String ?? ""
//FIXME: For debug
print(name)
guard let coordinates = city["coord"] as? [String: Any] else {
return
}
let lat = coordinates["lat"] as? Double ?? 0.0
let lon = coordinates["lon"] as? Double ?? 0.0
guard let main = city["main"] as? [String:Any] else {
return
}
let temperature = main["temp"] as? Int ?? 0
guard let weather = city["weather"] as? [Any] else { return }
guard let firstWeatherDescriptor = weather.first as? [String: Any] else { return }
let condition = firstWeatherDescriptor["main"] as? String ?? ""
let description = firstWeatherDescriptor["description"] as? String ?? ""
let iconName = firstWeatherDescriptor["icon"] as? String ?? "default_weather"
let newCity = City(context: coreDataStack.managedContext)
newCity.name = name
newCity.id = Int16(id)
newCity.renewData = newUpdateDate as NSDate
newCity.latitude = lat
newCity.longtitude = lon
let newWeather = Weather(context: coreDataStack.managedContext)
newWeather.city = newCity
newWeather.temperature = Int32(temperature)
newWeather.condition = condition
newWeather.conditionDescription = description
newWeather.iconName = iconName
}
}
从Core Data中读取数据
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//if no data was previous downloaded, than show Loading cell
if tableView.numberOfRows(inSection: 0) == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: updatingCellIdentifier, for: indexPath)
getLocation()
return cell
}
//FIXME: For debug
print("****")
print(indexPath)
print("****")
if indexPath.row == 0 {
return configureThisCityCell(at: indexPath)
} else {
return configureLocalCityCell(at: indexPath)
}
}
private func configureThisCityCell(at indexPath: IndexPath) -> CurrentCityTableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: currentCityCellIdentifier, for: indexPath) as! CurrentCityTableViewCell
//TODO: configure cell
let currentCity = fetchedResultController.object(at: indexPath)
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .short
dateFormatter.timeStyle = .short
cell.statusLabel.text = String(format: "Update at: %@", dateFormatter.string(from: currentCity.renewData! as Date))
cell.cityNameLabel.text = currentCity.name ?? NSLocalizedString("Unnown", comment: "Unnown city description")
cell.tempLabel.text = "\(String(describing: currentCity.weather!.temperature))°C"
cell.weatherDescriptionLabel.text = currentCity.weather?.conditionDescription
guard let conditionIconName = currentCity.weather?.iconName else { return cell }
guard let conditionIcon = UIImage(named: conditionIconName) else { return cell }
cell.weatherIconView.image = conditionIcon
return cell
}
private func configureLocalCityCell(at indexPath: IndexPath) -> LocalCityTableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: localCityCellIdentifier, for: indexPath) as! LocalCityTableViewCell
//TODO: configure cell
let currentCity = fetchedResultController.object(at: indexPath)
//FIXME: For debug
print(indexPath)
print(currentCity.name)
print(currentCity.id)
print("__________")
cell.cityNameLabel.text = currentCity.name ?? NSLocalizedString("Unnown", comment: "Unnown city description")
cell.tempLabel.text = "\(String(describing: currentCity.weather!.temperature))°C"
cell.weatherDescriptionLabel.text = currentCity.weather?.conditionDescription
guard let conditionIconName = currentCity.weather?.iconName else { return cell }
guard let conditionIcon = UIImage(named: conditionIconName) else { return cell }
cell.weatherIconView.image = conditionIcon
return cell
}
extension CurrentWeatherTableViewController: NSFetchedResultsControllerDelegate {
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
//TODO: this is works, but it is not solution, it's for time
do {
try controller.performFetch()
} catch let error as NSError {
print("Update error: \(error), \(error.userInfo)")
}
self.tableView.reloadData()
}
}