arrays - Swift - 将对象数组保存到核心数据,检索时只取回一个对象

标签 arrays swift core-data persistence

我正在从 API 获取 json 数据并从中填充一个 UITableview - 到目前为止一切正常。

问题是将数据保存到核心数据。据我所知-我正在正确保存数据,并且我已经调试看到实际上有 15 个对象已保存到核心数据中。我的问题是当试图从核心数据中检索数据时——我从整个 json 列表中只得到一个对象,通常它是第一个,但有时它是其他一些索引。

这是我的 VC:


import UIKit
import CoreData
import Kingfisher

class MoviesViewController: UITableViewController {

    let base_url = "https://api.androidhive.info/json/movies.json"
    let context = PersistanceService.context
    var moviesArray = [Movie]()

    override func viewDidLoad() {
        super.viewDidLoad()
        if loadData(){
            print("loading items from local presistancy")
        } else {
            print("fetching new data from api")
            dataFetchFromMoviesApi()
        }
        //dataFetchFromMoviesApi()
        tableView.estimatedRowHeight = 180
        tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "MovieCell")
    }



    //MARK: - TableView Delegate Method
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        performSegue(withIdentifier: "showMovieDetails", sender: moviesArray[indexPath.row])
    }

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }


    //MARK: - TableView Datasource Methods

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let movie = moviesArray[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "MovieCell", for: indexPath) as! TableViewCell
        cell.title.text = "Title: \(movie.title)"
        cell.rating.text = "Rating: \(String(movie.rating))"
        cell.releaseYear.text = "Release Year: \(String(movie.releaseYear))"
        cell.genre.text = "Genre: \(String(movie.genre[0]))"
        cell.movieImage.downloaded(from: movie.image)

        return cell

    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return moviesArray.count
    }

    //MARK: - Segue Method
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showMovieDetails" {
            let movieVC = segue.destination as! MovieDetailsViewController
            movieVC.selectedMovie = sender as? Movie
        }
    }



    //MARK: - Data Fetching Method

    func dataFetchFromMoviesApi(){
        httpRequest(urlForRequest: base_url) { [weak self] (data: Data?, error: Error?) in
            if error == nil { //no error - continue
                if let moviesData = data { //un-wrapping the data object
                    let decoder = JSONDecoder()
                    do {
                        let responseArray = try decoder.decode([Movie].self, from: moviesData)
                        //print(responseArray)
                        DispatchQueue.main.async {
                            self?.moviesArray = responseArray
                            self?.moviesArray.sort(by: {$0.releaseYear > $1.releaseYear})

                            for movie in self!.moviesArray {
                                let movieModel = MovieModel(context: self!.context)
                                movieModel.title = movie.title
                                movieModel.releaseYear = String(movie.releaseYear)
                                movieModel.rating = String(movie.rating)
                                movieModel.genre = movie.genre[0]
                                movieModel.image = movie.image
                            }
                            PersistanceService.saveContext()
                            self?.tableView.reloadData()
                        }
                    } catch {
                        print(error)
                    }
                }
            } else {
                //error fetching data
                print(error?.localizedDescription ?? "error with no description")
            }
        }
    }

    //MARK: - Http Request

    private func httpRequest(urlForRequest: String, completion: @escaping (Data?, Error?) -> Void){
        guard let url = URL(string: urlForRequest) else {return}
        let task = URLSession.shared.dataTask(with: url) { (data: Data?, urlResponse: URLResponse?, error: Error?) in
            if error == nil {
                //task was succfull
                completion(data, nil)
            } else {
                //task was unsuccessfull
                completion(nil, error)
            }
        }
        task.resume()
    }

    func saveData(){
        do {
            try context.save()
        } catch {
            print("error saving context, \(error.localizedDescription)")
        }
    }

    func loadData() ->Bool{
        let fetchRequest: NSFetchRequest<MovieModel> = MovieModel.fetchRequest()
        do {
            let movies = try PersistanceService.context.fetch(fetchRequest)
            print(movies.count)
            for movie in movies {
                let title = movie.title!
                let rating = Float(movie.rating!)!
                let image = movie.image!
                let genre = [movie.genre!]
                let releaseYear = Int(movie.releaseYear!)!
                let newMovie = Movie(title: title, image: image, rating: rating, releaseYear: releaseYear, genre: genre)
                self.moviesArray.append(newMovie)
                print("movies array count: \(moviesArray.count)")
                print("successfully loaded items")
                return true
            }
        } catch {
            print("error fetching from core data, \(error)")
            return false
        }
        return false
    }
}

我正在使用 2 种并行数据类型 - 一种是核心数据的电影实体,另一种是符合可编码协议(protocol)的电影结构,用于解码 json。因此,当取回获取请求时,我将其分配给电影对象,据我所知,这使电影对象成为我的电影实体的数组。我说得对吗?

希望有人能指出我正在做的错误。

最佳答案

你在 loadData 中把你的 return 放在了错误的地方,把它移出 for 循环

 for movie in movies {
     let title = movie.title!
     let rating = Float(movie.rating!)!
     let image = movie.image!
     let genre = [movie.genre!]
     let releaseYear = Int(movie.releaseYear!)!
     let newMovie = Movie(title: title, image: image, rating: rating, releaseYear: releaseYear, genre: genre)
     self.moviesArray.append(newMovie)
     print("movies array count: \(moviesArray.count)")
     print("successfully loaded items")
     // return true <-- This was wrong
 }
 return true //move it here

关于arrays - Swift - 将对象数组保存到核心数据,检索时只取回一个对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55950367/

相关文章:

ruby - 包含数组的散列到 ruby​​ 中的散列数组

ios - 将现有的核心数据镜像存储从可转换数据更改为二进制数据/允许外部存储

swift - 尝试从核心数据对象设置 UITextField 文本时在 prepareForSegue 中查找 nil

javascript - jQuery:如何创建每个项目有两个值的数组

java - 如何使用 javafx 绘制带有嵌套循环的 49 个矩形?

c++ - 从 boost::array 更改为 std::array 时出现错误

ios - 在 UITableViewCell 中使用 UIStepper 增加标签值

ios - 主详细信息应用程序indexPathForSelectedRow问题

ios - 如何获取视频完整时长和当前播放时间?

xcode - Core Data Saves 工具中 "Save duration"的单位是什么?