【问题标题】:Collection view does not display item when inserting item to DB (Core data)将项目插入数据库(核心数据)时,集合视图不显示项目
【发布时间】:2020-11-18 03:30:12
【问题描述】:

我有一个集合视图,当我添加游戏时应该显示游戏。在AddGameController 上,我添加了一个游戏并使用核心数据保存它。当 AddGameVC 关闭时,welcomeVC 会显示。但是,当从AddGameController 插入游戏时,集合视图不会更新,除非我终止应用程序以便在视图加载时获取对象。我怎样才能让它工作?

作为一种解决方案,我在插入时在 didChange 方法中添加了此代码 collectionView.reloadItems(at: [newIndexPath!]),并尝试在关闭 AddGameController 之前重新加载数据源,但没有使其工作。

更新: 当有插入时,我得到:线程 1:异常:“尝试将第 0 项插入第 0 节,但更新后第 0 节中只有 0 项”

Class AddGameController: UITableViewController {
        
     func textfieldValidation (){
        for textfield in textfieldCollection {
            if  textfield.text!.isEmpty || segmented.selectedSegmentIndex == -1 {
                alertMethod()
            } else {
                self.dismiss(animated: true, completion: nil)
            }
        }
    }
    

      @IBAction func addButtonPressed(_ sender: UIButton) {

        save()
        textfieldValidation()
    }

    func save(){
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let newGame = GameMo(context: appDelegate.persistentContainer.viewContext)
        newGame.goal = (Int32(goal.text ?? "0")!)
        newGame.rivalGoal = (Int32(rivalGoal.text ?? "0")!)
        newGame.shot = (Int32(shots.text ?? "0")!)
        newGame.rivalShot = (Int32(rivalsShots.text ?? "0")!)
        newGame.nouveau =  true
        newGame.date = DateManager.dateLong()
        appDelegate.saveContext()

    }

}
Class WelcomeViewController: UICollectionViewDelegate, UICollectionViewDataSource {
         var ops: [BlockOperation] = []
        lazy var context : NSManagedObjectContext = {
        let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)

        let appDelegate = UIApplication.shared.delegate as! AppDelegate

        return appDelegate.persistentContainer.viewContext

    }()

    

    lazy var fetchRequestController : NSFetchedResultsController<GameMo> = {

        let fetchRequest = NSFetchRequest<GameMo>(entityName: "Game")

        fetchRequest.sortDescriptors = [NSSortDescriptor(key: "date", ascending: false)]

        let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)

        frc.delegate = self

        do {
            try frc.performFetch()

            if let fetchedObjects = frc.fetchedObjects {

                print("Fetch Request Activated")

                self.gamesMo = fetchedObjects


            }

        } catch{

            fatalError("Failed to fetch entities: \(error)")

        }

        return frc

    }()


       override func viewDidLoad() {
        super.viewDidLoad()
        fetchRequestController.delegate = self
        try? fetchRequestController.performFetch()

    }
      deinit {
        for o in ops { o.cancel() }
        ops.removeAll()
    }

      func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

        return gamesMo?.filter{$0.nouveau == true}.count ?? 0

    }

  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        if let gameIndex = gamesMo?.filter({$0.nouveau == true})[indexPath.row] {

            let userGameScore = gameIndex.goal

            let rivalGameScore = gameIndex.rivalGoal

            if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FormCell", for: indexPath) as? FormCollectionViewCell {

                cell.setCell(userScores: Int(userGameScore), rivalScores: Int(rivalGameScore) )
                return cell

            }

        }

        return UICollectionViewCell ()

    }

}
extension WelcomeViewController: NSFetchedResultsControllerDelegate {
 func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
           
        }
        
        func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
            
           switch type {
                case .insert:
                    print("insert")
                    print(gamesMo?.count)
                    ops.append(BlockOperation(block: { [weak self] in
                        self?.collectionView.insertItems(at: [newIndexPath!])
                       
                    }))
                case .delete:
                    ops.append(BlockOperation(block: { [weak self] in
                        self?.collectionView.deleteItems(at: [indexPath!])
                    }))
                case .update:
                    ops.append(BlockOperation(block: { [weak self] in
                        self?.collectionView.reloadItems(at: [indexPath!])
                    }))
                case .move:
                    ops.append(BlockOperation(block: { [weak self] in
                        self?.collectionView.moveItem(at: indexPath!, to: newIndexPath!)
                    }))
                @unknown default:
                    break
            }
        }
        
        func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
            print("TableView endupdates")
            
            collectionView.performBatchUpdates({ () -> Void in
                for op: BlockOperation in self.ops { op.start() }
            }, completion: {(finished) -> Void in self.ops.removeAll() })
        }
    
}

【问题讨论】:

标签: ios swift core-data uicollectionview


【解决方案1】:

您可以简单地在viewDidAppearWelcomeViewController 中执行performFetch 来解决此问题。

class WelcomeViewController: UIViewController {
    //...
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        fetchRequestController.delegate = self
        try? fetchRequestController.performFetch()
    }
}

修改save()以使用saveContext保存核心数据上下文。

func save(){
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    //...
    appDelegate.saveContext()
}

【讨论】:

  • @Vangola 也许保存在您的自定义保存方法中不起作用。尝试在自定义 save() 方法中添加 appDelegate.save()
  • 保存方法有效,因为当我使用 viewDidLoad 中的 performFetch 重新启动应用程序时,我可以看到所有添加的项目。
  • applicationwillterminate 方法中有一个保存。这将是保存以在重新启动时工作的原因。
  • 我更新了代码。但在我的 Xcode 中,我在 save 方法中有 appDelegate.saveContext()。当我按下 DB Browser for SQL lite 中的保存按钮时,我可以看到一个游戏。 `appDelegate.saveContext() 不是问题。
  • 如果保存不是问题,那么通过获取viewDidAppear 应该可以解决问题。您还有什么要补充的吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-11
相关资源
最近更新 更多