NSFetchedResultsController返回重复项

时间:2017-09-18 02:39:03

标签: ios swift core-data nsfetchedresultscontroller

我解析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()
}
}

0 个答案:

没有答案