Swift - 将对象数组保存到核心数据,检索时只取回一个对象
Swift - saving array of objects to core data, getting only one object back when retrieving
我正在从 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: {[=11=].releaseYear > .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 种并行数据类型 - 一种是核心数据的电影实体,另一种是符合可编码协议的电影结构,另一种是解码 json。因此,当取回获取请求时,我将其分配给电影对象,据我所知,这使电影对象成为我的电影实体的数组。我说得对吗?
希望有人能指出我正在做的错误。
您将 return 放在 loadData
中的错误位置,请将其移出 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
我正在从 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: {[=11=].releaseYear > .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 种并行数据类型 - 一种是核心数据的电影实体,另一种是符合可编码协议的电影结构,另一种是解码 json。因此,当取回获取请求时,我将其分配给电影对象,据我所知,这使电影对象成为我的电影实体的数组。我说得对吗?
希望有人能指出我正在做的错误。
您将 return 放在 loadData
中的错误位置,请将其移出 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