【问题标题】:Problem with saving data using Core Data in swift快速使用Core Data保存数据的问题
【发布时间】:2021-11-06 21:21:00
【问题描述】:

我正在尝试save data to the core data,然后将其显示在另一个视图控制器上。我有一个table view with custom cell, which have a button。我创建了一个selector,所以当我们点击每个单元格中的按钮时,它应该保存单元格中的所有数据。这是我的parent view controller

import UIKit
import SafariServices
import CoreData

class ViewController: UIViewController, UISearchBarDelegate {

    @IBOutlet weak var pecodeTableView: UITableView!
    
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    
    var savedNews = [SavedNews]()
    
    var newsTitle: String?
    var newsAuthor: String?
    var urlString: String?
    var newsDate: String?
    var isSaved: Bool = false
    
    private var articles = [Article]()
    private var viewModels = [NewsTableViewCellViewModel]()
    
    private let searchVC = UISearchController(searchResultsController: nil)
    
    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()
        createSearchBar()
        loadNews()
        saveNews()
        countNewsToCategory()
        
    }
    
    @IBAction func goToFavouritesNews(_ sender: UIButton) {
        performSegue(withIdentifier: S.Segues.goToFav, sender: self)
    }
    
    private func fetchAllNews() {
        APICaller.shared.getAllStories { [weak self] result in
            switch result {
            case .success(let articles):
                self?.articles = articles
            self?.viewModels = articles.compactMap({
                NewsTableViewCellViewModel(author: $0.author ?? "Unknown", title: $0.title, subtitle: $0.description ?? "No description", imageURL: URL(string: $0.urlToImage ?? "")
                )
            })
                DispatchQueue.main.async {
                    self?.pecodeTableView.reloadData()
                }
                
            case .failure(let error):
                print(error)
            }
        }
    }
    
    private func createSearchBar() {
        navigationItem.searchController = searchVC
        searchVC.searchBar.delegate = self
    }
}

extension ViewController: UITableViewDelegate, UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 120
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return viewModels.count
    }
    
    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
        cell.configure(with: viewModels[indexPath.row])
        cell.saveNewsBtn.tag = indexPath.row
        cell.saveNewsBtn.addTarget(self, action: #selector(didTapCellButton(sender:)), for: .touchUpInside)
        return cell
    }
    
    @objc func didTapCellButton(sender: UIButton) {
        guard viewModels.indices.contains(sender.tag) else { return }
        print("Done")// check element exist in tableview datasource
        if !isSaved {
            saveNews()
            print("success")
        }

        //Configure selected button or update model
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        let article = articles[indexPath.row]
        
        
        
        guard let url = URL(string: article.url ?? "") else {
            return
        }
        
        let vc = SFSafariViewController(url: url)
        present(vc, animated: true)
    }
    
    //Search
    
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        guard let text = searchBar.text, !text.isEmpty else {
            return
        }
        APICaller.shared.Search(with: text) { [weak self] result in
            switch result {
            case .success(let articles):
                self?.articles = articles
            self?.viewModels = articles.compactMap({
                NewsTableViewCellViewModel(author: $0.author ?? "Unknown", title: $0.title, subtitle: $0.description ?? "No description", imageURL: URL(string: $0.urlToImage ?? "")
                )
            })
                DispatchQueue.main.async {
                    self?.pecodeTableView.reloadData()
                    self?.searchVC.dismiss(animated: true, completion: nil)
                }
                
            case .failure(let error):
                print(error)
            }
        }
    }
}

extension ViewController {
    func loadNews() {
        let request: NSFetchRequest<SavedNews> = SavedNews.fetchRequest()
        
        do {
            let savedNews = try context.fetch(request)
            
            //Handle saved news
            if savedNews.count > 0 {
                isSaved = true
            }
        } catch {
            print("Error fetching data from context \(error)")
        }
    }
    
    func saveNews() {
        //Initialize the context
        let news = SavedNews(context: self.context)
        
        //Putting data
        news.title = newsTitle
        news.author = newsAuthor
        news.publishedAt = newsDate
        news.url = urlString
        
        do {
            try context.save()
        } catch {
            print("Error when saving data \(error)")
        }
    }
    
    func countNewsToCategory() {
        //Initialize the context
        let request: NSFetchRequest<SavedNews> = SavedNews.fetchRequest()
        let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [
        ])
        request.predicate = predicate
        do {
            savedNews = try context.fetch(request)
        } catch {
            print("Error fetching data from category \(error)")
        }
    }
}

我不知道问题出在哪里,我创建了一个correct data model,但无法保存数据。这是我的model

import Foundation

struct APIResponse: Codable {
    let articles: [Article]
}

struct Article: Codable {
    let author: String?
    let source: Source
    let title: String
    let description: String?
    let url: String?
    let urlToImage: String?
    let publishedAt: String
}

struct Source: Codable {
    let name: String
}

还有我的model in Core Data

我的second view controller,我想向其显示数据:

import UIKit
import CoreData

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

    override func viewDidLoad() {
        super.viewDidLoad()
        
        favTableView.delegate = self
        favTableView.delegate = self
        
        loadSavedNews()
        
        favTableView.register(UINib(nibName: S.FavouriteCell.favouriteCell, bundle: nil), forCellReuseIdentifier: S.FavouriteCell.favouriteCellIdentifier)

        // Do any additional setup after loading the view.
    }

}

extension FavouriteNewsViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return savedNews.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = favTableView.dequeueReusableCell(withIdentifier: S.FavouriteCell.favouriteCellIdentifier, for: indexPath) as! FavouritesCell
        
        print(savedNews)
        let article = savedNews[indexPath.row]
        if let articleTitle = article.title {
            cell.favTitle.text = articleTitle
        }
        if let articleAuthor = article.author {
            cell.favAuthor.text = articleAuthor
        }
        
        if let articleDesc = article.desc {
            cell.favDesc.text = article.desc
        }
        
        return cell
    }
    
    
}

extension FavouriteNewsViewController {
    func loadSavedNews() {
        let request: NSFetchRequest<SavedNews> = SavedNews.fetchRequest()
        
        do {
            savedNews = try context.fetch(request)
        } catch {
            print("Error fetching data from context \(error)")
        }
    }
    
    func deleteNews(at indexPath: IndexPath) {
        // Delete From NSObject
        context.delete(savedNews[indexPath.row])
        
        // Delete From current News list
        savedNews.remove(at: indexPath.row)
        
        // Save deletion
        do {
            try context.save()
        } catch {
            print("Error when saving data \(error)")
        }
    }
}

【问题讨论】:

  • 真正的问题是,你被缺乏设计和架构所困扰。视图控制器不是蛋糕糊,您可以在其中混合构成整个应用程序的所有成分。因此,第一步是重构组件,将 Clean Code 原则应用于 VC,使其易于理解,从而解决数据竞争和其他设置问题。

标签: ios json swift database core-data


【解决方案1】:

您没有分配您尝试保存的属性

 newsTitle,newsAuthor,newsDate,urlString
     

似乎这些属性的值为零。确保这些属性在保存之前具有有效值。

【讨论】:

  • 不明白,我在 SaveNews() 里做了这个
  • 是的,但这些属性的值为 nil 。分配他们 newsTitle = "value"
  • 您正在从视图控制器中获取值,但是您在哪里设置它们?
  • 不太明白
  • func saveNews() { //初始化上下文 let news = SavedNews(context: self.context) newsTitle = "newTilteValue" newsAuthor = "authorValue" newsDate = "dateValue" urlString = "urlString" / /放数据 news.title = newsTitle news.author = newsAuthor news.publishedAt = newsDate news.url = urlString do { try context.save() } catch { print("保存数据时出错(错误)") } }跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-28
  • 1970-01-01
  • 2018-05-09
  • 1970-01-01
  • 1970-01-01
  • 2015-10-15
  • 1970-01-01
相关资源
最近更新 更多