首页 > 解决方案 > 如何从一个视图控制器保存数据并使用核心数据在另一个视图控制器中显示

问题描述

我需要帮助解决一个问题core data。我有一个带有两个视图控制器的新闻应用程序。在main view controller我正在自定义单元格的表格视图中加载新闻数据。在这里,我有一个button, on which should I tap and save news to another view controller. 它现在看起来如何:它看起来如何所以当我们tap on this blue button, it should save news from the cell and display on second view controller. 我创建了一个core data model这样的:核心数据模型这是代码my first view controller

import UIKit
import SafariServices
import CoreData

class ViewController: UIViewController, UISearchBarDelegate, UpdateTableViewDelegate {
    
    @IBOutlet weak var pecodeTableView: UITableView!
    
    private var articles = [News]()
//    private var viewModels = [NewsTableViewCellViewModel]()
    private var viewModel = NewsListViewModel()
    
    var newsTitle: String?
    var newsAuthor: String?
    var newsDesc: String?
    var urlString: String?
    var newsDate: String?
    
    private let searchVC = UISearchController(searchResultsController: nil)
    
    var selectedRow = Int()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        pecodeTableView.delegate = self
        pecodeTableView.dataSource = self
        
        pecodeTableView.register(UINib(nibName: S.CustomCell.customNewsCell, bundle: nil), forCellReuseIdentifier: S.CustomCell.customCellIdentifier)
        
//        fetchAllNews()
        viewModel.delegate = self
        
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        categoryMenu()
        loadData()
    }
    
    private func loadNewsData(api: String){
        let apiService = APIService(categoryCode: api)
        apiService.getNewsData {(result) in
            switch result{
            case .success(let NewsOf):
                CoreData.sharedInstance.saveDataOf(news: NewsOf.articles)
            case .failure(let error):
                print("Error processing json data: \(error)")
               
            }
        }
    }
    
    func reloadData(sender: NewsListViewModel) {
        self.pecodeTableView.reloadData()
    }
    
    //MARK: - Networking
    private func loadData(){
        viewModel.retrieveDataFromCoreData()
    }
    
    //MARK: - UIView UImenu
    func categoryMenu(){
        var categoryAction: UIMenu{
            let menuAction = Category.allCases.map { (item) -> UIAction in
                let name = item.rawValue
                return UIAction(title: name.capitalized, image: UIImage(systemName: item.systemImage)) { [weak self](_) in
                    self?.loadNewsData(api: name)
                    self?.loadData()
                    self?.reloadData(sender: self!.viewModel)
                }
            }
            return UIMenu(title: "Change Category", children: menuAction)
        }
        let categoryButton = UIBarButtonItem(image: UIImage(systemName: "scroll"), menu: categoryAction)
        navigationItem.leftBarButtonItem = categoryButton
    }
    
    @IBAction func goToFavouritesNews(_ sender: UIButton) {
        performSegue(withIdentifier: S.Segues.goToFav, sender: self)
    }
    
    private func createSearchBar() {
        navigationItem.searchController = searchVC
        searchVC.searchBar.delegate = self
    }
   
}



extension ViewController: UITableViewDelegate, UITableViewDataSource {

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 150
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return viewModel.numberOfRowsInSection(section: section)
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: S.CustomCell.customCellIdentifier, for: indexPath) as? CustomNewsCell
        let object = viewModel.object(indexPath: indexPath)!
        cell?.setCellWithValuesOf(object)
        cell?.saveNewsBtn.tag = indexPath.row
        cell?.saveNewsBtn.addTarget(self, action: #selector(didTapCellButton(sender:)), for: .touchUpInside)
        return cell!
    }
    
    @objc func didTapCellButton(sender: FavouritesCell) {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let context: NSManagedObjectContext = appDelegate.persistentContainer.viewContext
        let entity = NSEntityDescription.entity(forEntityName: "SavedNews", in: context)
        let newNewsSave = SavedNews(entity: entity!, insertInto: context)
        newNewsSave.author = newsAuthor
        newNewsSave.desc = newsDesc
        newNewsSave.title = newsTitle
        do {
            try context.save()
            savedNews.append(newNewsSave)
            navigationController?.popViewController(animated: true)
        } catch {
            print("Error saving")
        }
        
        print("Done")
        }

我还想向您展示my parsing functions and model*APIService.swift*

import Foundation

class APIService{
    
    private var dataTask: URLSessionDataTask?
    
    public let resourceURL: URL
    private let API_KEY = "e2a69f7f9567451ba484c85614356c30"
    private let host = "https://newsapi.org"
    private let headlines = "/v2/top-headlines?"
    
    init(categoryCode: String){
        let resourceString = "\(host)\(headlines)country=us&category=\(categoryCode)&apiKey=\(API_KEY)"
        print(resourceString)
        
        guard let resourceURL = URL(string: resourceString) else {
            fatalError()
        }
        self.resourceURL = resourceURL
    }
    //MARK: - Get News
    func getNewsData(completion: @escaping (Result<Articles, Error>) -> Void){
        dataTask = URLSession.shared.dataTask(with: resourceURL) { (data, response, error) in
            if let error = error{
                completion(.failure(error))
                print("DataTask error: - \(error.localizedDescription)")
            }
            
            guard let response = response as? HTTPURLResponse else{
                print("Empty Response")
                return
            }
            print("Response status code: - \(response.statusCode)")
            
            guard let data = data else {
                print("Empty Data")
                return
            }
            do{
                let decoder = JSONDecoder()
                let jsonData = try decoder.decode(Articles.self, from: data)
                
                DispatchQueue.main.async {
                    completion(.success(jsonData))
                }
            }catch let error{
                completion(.failure(error))
            }
        }
        dataTask?.resume()
    }
}

这是NewsModel.swift

import Foundation

struct Articles: Codable {
    let articles: [News]
    
    private enum CodingKeys: String, CodingKey{
        case articles = "articles"
    }
}

struct News: Codable {
    let author: String?
    let source: Source
    let title: String
    let description: String?
    let url: URL?
    let urlToImage: URL?
    let publishedAt: String?
    
    private enum CodingKeys: String, CodingKey{
        case author = "author"
        case title = "title"
        case url = "url"
        case urlToImage = "urlToImage"
        case publishedAt = "publishedAt"
        case description = "description"
        case source = "source"
    }
}

struct Source: Codable {
    let name: String?
}

这是我的代码CustomNewsCell.swift

import UIKit

protocol CustomNewsDelegate: AnyObject {
    func btnFavPress(cell: CustomNewsCell)
}

private var loadImage = LoadToImage()
private var formatDate = FormatDate()

class CustomNewsCell: UITableViewCell {
    
    weak var delegate: CustomNewsDelegate?
    
    @IBOutlet weak var saveNewsBtn: UIButton!
    @IBOutlet weak var imageOutlet: UIImageView!
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var descLabel: UILabel!
    @IBOutlet weak var authorLabel: UILabel!
    @IBOutlet weak var dateLabel: UILabel!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
    
    func setCellWithValuesOf(_ news: SavedNews){
        updateUI(title: news.title, url: news.url, urlToImage: news.urlToImage, publishedAt: news.publishedAt, author: news.author ?? "No author", description: news.desc, source: news.source)
    }
    
    private func updateUI(title: String?, url: URL?, urlToImage: URL?, publishedAt: String?, author: String, description: String?, source: String?){
        
        //title
        self.titleLabel.text = title
        self.authorLabel.text = author
        self.descLabel.text = description
        
        
        //date
        let dateString = formatDate.formatDate(from: publishedAt ?? "")
        let date = formatDate.formatDateString(from: dateString)
        self.dateLabel.text = date
        
        
        //image
        guard let urlToImageString = urlToImage else {return}
        imageOutlet.image = nil
        loadImage.getImageDataFrom(url: urlToImageString) { [weak self] data in
            guard let data = data, let image = UIImage(data: data) else{
                DispatchQueue.main.async {
                    self?.imageOutlet.image = UIImage(named: "noImage")
                }
                return
            }
            self?.imageOutlet.image = image
        }
        
    }
    
    @IBAction func saveBtnPressed(_ sender: UIButton) {
        delegate?.btnFavPress(cell: self)
    }
}

我第一次尝试使用delegate method for this blue button,但现在你可以看到我创建了一个selector method. 也许它不正确,需要修复它。这是 中的代码second view controller,应该show saved news from first view controller

import UIKit
import CoreData

var savedNews = [SavedNews]()

class FavouriteNewsViewController: UIViewController {
    
    @IBOutlet weak var favTableView: UITableView!
    
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    
    var result: [SavedNews] = []
    
    var newsTitleNew: String?
    var newsDescNew: String?
    var newsAuthor: String?

    override func viewDidLoad() {
        super.viewDidLoad()

        favTableView.delegate = self
        favTableView.delegate = self
        fetch()
//        loadSavedNews()
        
        favTableView.register(UINib(nibName: S.FavouriteCell.favouriteCell, bundle: nil), forCellReuseIdentifier: S.FavouriteCell.favouriteCellIdentifier)
        

        // Do any additional setup after loading the view.
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)
//        fetch()
        favTableView.reloadData()
    }
    
    @IBAction func goToNewsFeed(_ sender: UIButton) {
        performSegue(withIdentifier: S.Segues.goToNewsFeed, sender: self)
    }
    
}

extension FavouriteNewsViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return savedNews.count
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 140
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = favTableView.dequeueReusableCell(withIdentifier: S.FavouriteCell.favouriteCellIdentifier, for: indexPath) as! FavouritesCell
        
        let newRslt: SavedNews!
        newRslt = savedNews[indexPath.row]
        cell.favAuthor.text = newRslt.author
        cell.favDesc.text = newRslt.desc
        cell.favTitle.text = newRslt.title
        
        return cell
    }
    
    func fetch() {
        let request = NSFetchRequest<SavedNews>(entityName: "SavedNews")
        
        do {
            savedNews = try context.fetch(request)
        } catch {
            print(error)
        }
    }
}

和代码cell for this controller

import UIKit
import CoreData

class FavouritesCell: UITableViewCell {

    @IBOutlet weak var favImage: UIImageView!
    @IBOutlet weak var favTitle: UILabel!
    @IBOutlet weak var favDesc: UILabel!
    @IBOutlet weak var favAuthor: UILabel!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
    
}

如果有人可以帮助解决这个问题,那将是惊人的。因为我真的不知道该怎么做。谢谢!

标签: iosjsonswiftdatabasecore-data

解决方案


推荐阅读