每次我显示视图控制器时,CoreData 都会再次添加到表视图中(重复数据)

Posted

技术标签:

【中文标题】每次我显示视图控制器时,CoreData 都会再次添加到表视图中(重复数据)【英文标题】:CoreData gets added to Table View AGAIN Every Time I Show View Controller (duplicates data) 【发布时间】:2021-05-31 23:36:56 【问题描述】:

我按照这个教程 https://www.youtube.com/watch?v=35mKM4IkHS8&lc=UgztyK4XjUuAOrKk0XJ4AaABAg.9LtwRc_M0Gv9Nt8GIlAzDo

基本上我做了一个具有核心数据保存功能的记事本应用程序。 我在另一个视图控制器上制作了这个应用程序 所以有 MainViewController > NoteViewViewController 我第一次单击记事本部分时,它可以很好地加载核心数据,但是如果我关闭 NoteView 并重新打开它 - 它会复制核心数据中所有保存的笔记 这里是。注意视图控制器

import UIKit
import CoreData

var noteList = [Note]()


class NoteTableView: UITableViewController



    
    
    
    func nonDeletedNotes() -> [Note]
    
        var noDeleteNoteList = [Note]()
        for note in noteList
        
            if(note.deletedDate == nil)
            
                noDeleteNoteList.append(note)
            
        
        return noDeleteNoteList
    
    
    
    var firstLoad = true
    
    override func viewDidLoad() 
        
        if(firstLoad == true)
        
        
        
            firstLoad = false
            let appDelegate = UIApplication.shared.delegate as! AppDelegate
            let context: NSManagedObjectContext = appDelegate.persistentContainer.viewContext
            let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Note")
            do 
                let results:NSArray = try context.fetch(request) as NSArray
                for result in results
                
                    let note = result as! Note
                    noteList.append(note)
                
            
            catch
            
                print("Fetch Failed")
            
            
        
    
    
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->
    UITableViewCell
    
    
        let noteCell = tableView.dequeueReusableCell(withIdentifier: "noteCellID", for: indexPath) as! NoteCell
        
        let thisNote: Note!
        thisNote = nonDeletedNotes()[indexPath.row]
        
        noteCell.titleLabel.text = thisNote.title
        noteCell.descLabel.text = thisNote.desc1
        
        return noteCell
        
    
   
    
    
    
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    
        return nonDeletedNotes().count
    
    override func viewDidAppear(_ animated: Bool) 
        tableView.reloadData()
    
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
    
        self.performSegue(withIdentifier: "editNote", sender: self)
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?)
    
        if(segue.identifier == "editNote")
        
            let indexPath = tableView.indexPathForSelectedRow!
            
            let noteDetail = segue.destination as? FocusWheelViewController
            
            let selectedNote : Note!
            selectedNote = nonDeletedNotes()[indexPath.row]
            noteDetail!.selectedNote = selectedNote
            
            tableView.deselectRow(at: indexPath, animated: true)
        
    
  

    

我确定有一个通用的解决方案,但我不确定它是什么,也无法关注提出类似问题的帖子,因为我的代码不同,而且我确实不太了解机制对此应用其他答案

【问题讨论】:

【参考方案1】:

我发现最简单的解决方案是添加这两行,以便每次刷新表格视图,然后加载数据

noteList.removeAll()
tableView.reloadData()

所以代码看起来像这样:

 var firstLoad = true
    
    override func viewDidLoad() 
        
        if(firstLoad == true)
        
        
        
            noteList.removeAll() //NEWCODE
            tableView.reloadData() //NEWCODE
            firstLoad = false
            let appDelegate = UIApplication.shared.delegate as! AppDelegate
            let context: NSManagedObjectContext = appDelegate.persistentContainer.viewContext
            let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Note")
            do 
                let results:NSArray = try context.fetch(request) as NSArray
                for result in results
                
                    let note = result as! Note
                    noteList.append(note)
                
            
            catch
            
                print("Fetch Failed")
            
            
        
    

【讨论】:

【参考方案2】:

问题是var firstLoad = true。因为每次控制器启动时,firtLoad 始终为 true,应用程序将从 Coredata 获取数据并附加到 noteList。

解决方案是 UserDefaults。第一次运行应用程序时,firstLoad 始终为 true。所以需要将firstLoad的值bool保存到UserDefaults

// Set
UserDefaults.standard.setValue(true, forKey: "firstLoad")
// Get
UserDefaults.standard.bool(forKey: "firstLoad")

import UIKit
import CoreData

class NoteTableView: UITableViewController
    
    var noteList = [Note]()
    func nonDeletedNotes() -> [Note]
        var noDeleteNoteList = [Note]()
        for note in noteList 
            if(note.deletedDate == nil) 
                noDeleteNoteList.append(note)
            
        
        return noDeleteNoteList
    
    
    override func viewDidLoad() 
        if noteList.count == 0 
            if(UserDefaults.standard.bool(forKey: "firstLoad") == true)
                let appDelegate = UIApplication.shared.delegate as! AppDelegate
                let context: NSManagedObjectContext = appDelegate.persistentContainer.viewContext
                let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Note")
                do 
                    let results:NSArray = try context.fetch(request) as NSArray
                    for result in results
                    
                        let note = result as! Note
                        noteList.append(note)
                        UserDefaults.standard.setValue(false, forKey: "firstLoad")
                    
                
                catch 
                    print("Fetch Failed")
                
                
            
         
            else 
                UserDefaults.standard.setValue(false, forKey: "firstLoad")
            
        
        
    

也许你在从 CoreData 获取数据时需要检查重复值。

【讨论】:

非常感谢您的回答,它解决了重复问题,但在应用程序关闭并重新打开后似乎没有保留数据。可能是我的菜鸟错误,但你怎么看? 我认为当你停止应用程序时,一切都会被中止以释放内存。然后,当您再次启动时,应用程序将存储来自 CoreData 的数据。这是必要的,一旦应用关闭,您将无法保留数据。 嗯,对于旧代码,它完美地存储了数据。如果我关闭并重新打开应用程序,我所有的笔记都还在。我不确定发生了什么变化 那么,你可以用viewWillAppear 替换viewDidLoad 吗?因为viewWillAppear 会在您激活控制器时调用。 这真的很有帮助,它也停止了复制,但它也阻止它在应用程序关闭并重新打开后加载保存的笔记,就像在 kiete 的帮助下一样。这真的很有趣,我还不确定为什么会发生这种情况

以上是关于每次我显示视图控制器时,CoreData 都会再次添加到表视图中(重复数据)的主要内容,如果未能解决你的问题,请参考以下文章

线程化核心数据和 UINavigationController

每次呈现时,视图控制器原点都会发生变化

每次推送新路线时,都会再次显示最后的 Flutter SnackBar

视图控制器仅在第一次保存到 coredata 时填写我的表单

CoreData NSManagedObject 已损坏

再次显示视图控制器时自动布局中断