Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios NSFetchedResultsController错误:尝试从节0中删除项,该节在使用userInfo(null)进行更新之前仅包含1项_Ios_Swift_Core Data_Nsfetchedresultscontroller - Fatal编程技术网

Ios NSFetchedResultsController错误:尝试从节0中删除项,该节在使用userInfo(null)进行更新之前仅包含1项

Ios NSFetchedResultsController错误:尝试从节0中删除项,该节在使用userInfo(null)进行更新之前仅包含1项,ios,swift,core-data,nsfetchedresultscontroller,Ios,Swift,Core Data,Nsfetchedresultscontroller,我有一个使用核心数据的应用程序。里面有帖子,每个帖子都有很多标签。每个标签都有许多帖子 我有一个主视图控制器,它显示所有标记的集合视图。此collectionView的数据源由NSFetchedResultsController提供电源 class HomeViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource,NSFetchedResultsControllerDelegate

我有一个使用核心数据的应用程序。里面有帖子,每个帖子都有很多标签。每个标签都有许多帖子

我有一个主视图控制器,它显示所有标记的集合视图。此collectionView的数据源由NSFetchedResultsController提供电源

class HomeViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource,NSFetchedResultsControllerDelegate {

    @IBOutlet weak var latestTagsCollectionView: UICollectionView!

    var fetchedResultsController: NSFetchedResultsController<Tag>!
    var blockOperations: [BlockOperation] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        self.latestTagsCollectionView.dataSource = self
        self.latestTagsCollectionView.delegate = self
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        //1
        guard let appDelegate =
            UIApplication.shared.delegate as? AppDelegate else {
                return
        }
        let managedContext =
            appDelegate.persistentContainer.viewContext
        //2
        let fetchRequest =
            NSFetchRequest<NSManagedObject>(entityName: "Tag")
        //3
        fetchRequest.sortDescriptors = []

        fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedContext, sectionNameKeyPath: nil, cacheName: nil) as? NSFetchedResultsController<Tag>
        fetchedResultsController.delegate = self

        do {
            try fetchedResultsController.performFetch()
        } catch let error as NSError {
            print("Could not fetch. \(error), \(error.userInfo)")
        }
    }

    func configure(cell: UICollectionViewCell, for indexPath: IndexPath) {

        guard let cell = cell as? TagCollectionViewCell else {
            return
        }
        print(indexPath,"indexPath")
        let tag = fetchedResultsController.object(at: indexPath)
        guard let timeAgo = tag.mostRecentUpdate as Date? else { return }
        cell.timeAgo.text = dateFormatter.string(from: timeAgo)
        if let imageData = tag.mostRecentThumbnail {
            cell.thumbnail.image = UIImage(data:imageData as Data,scale:1.0)
        } else {
            cell.thumbnail.image = nil
        }
        cell.tagName.text = tag.name
        cell.backgroundColor = UIColor.gray
    }

    //CollectionView Stuff
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        guard let sectionData = fetchedResultsController.sections?[section] else {
            return 0
        }
        return sectionData.numberOfObjects
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = latestTagsCollectionView.dequeueReusableCell(withReuseIdentifier: "latestTagCell", for: indexPath) as! TagCollectionViewCell
        configure(cell: cell, for: indexPath)
        return cell
    }

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
                             didChange anObject: Any,
                             at indexPath: IndexPath?,
                             for type: NSFetchedResultsChangeType,
                             newIndexPath: IndexPath?){
        switch type {
        case .insert:
            print("Insert Object: \(String(describing: newIndexPath))")
            blockOperations.append(
                BlockOperation(block: { [weak self] in
                    if let this = self {
                        this.latestTagsCollectionView!.insertItems(at: [newIndexPath!])
                    }
                })
            )
        case .update:
            blockOperations.append(
                BlockOperation(block: { [weak self] in
                    if let this = self {
                        this.latestTagsCollectionView!.reloadItems(at: [newIndexPath!])
                    }
                })
            )
        case .move:
            blockOperations.append(
                BlockOperation(block: { [weak self] in
                    if let this = self {
                        this.latestTagsCollectionView!.moveItem(at: indexPath!, to: newIndexPath!)
                    }
                })
            )
        case .delete:
            print("deleted record")
            blockOperations.append(
                BlockOperation(block: { [weak self] in
                    if let this = self {
                        this.latestTagsCollectionView!.deleteItems(at: [newIndexPath!])
                    }
                })
            )
        default: break
        }
    }

    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        latestTagsCollectionView!.performBatchUpdates({ () -> Void in
            for operation: BlockOperation in self.blockOperations {
                operation.start()
            }
        }, completion: { (finished) -> Void in
            self.blockOperations.removeAll(keepingCapacity: false)
        })
    }

    deinit {
        // Cancel all block operations when VC deallocates
        for operation: BlockOperation in blockOperations {
            operation.cancel()
        }
        blockOperations.removeAll(keepingCapacity: false)
    }
将.insert大小写应用于NSFetchedResultsController的回调方法时打印

然后我添加了一个带有两个标签的帖子:“一”、“二”


为什么试图在此处删除项目1。。。我真的不明白这个错误消息。我认为它应该只是在新的索引路径插入一个项,因为在数据库中创建了一个新的标记“Two”。这是怎么回事

您的问题是由于在
.update
案例中使用
newindepath
而不是
indepath
造成的

将现有标记指定给帖子时,该
标记
对象将更新。这会导致将
.updated
事件发布到
NSFetchResultsControllerDelegate

在委托方法中,
newindepath
表示处理插入后对象的索引路径,而
indepath
表示插入前对象的索引路径

各国的文件:

在批处理操作中,删除是在插入之前处理的。这意味着删除的索引是相对于批处理操作之前集合视图状态的索引进行处理的,插入的索引是相对于批处理操作中所有删除之后状态的索引进行处理的

由于插入是最后执行的,当您尝试重新加载
newindepath
时会出现异常,因为您尝试重新加载尚未插入的元素

在本例中,将代码更改为引用
indepath
,可以解决问题

 case .update:
     blockOperations.append(
         BlockOperation(block: { [weak self] in
             if let this = self {
                 this.latestTagsCollectionView!.reloadItems(at: [indexPath!])
             }
         })
     )

此外,您只需更新
Post
标记
;由于存在反向参考,核心数据将负责更新其他对象

您的模型中是否设置了正确的反向关系?如果是这样,您应该将标记添加到post或将post添加到标记中,但不能同时添加两者。@Paulw11标记实体与目标post和反向“标记”有一种称为post的关系。Post实体与目标标记和反向“Post”有一种称为标记的关系。我读到这是你如何建立一个多对多的关系,尽管反过来有点混乱。我如何知道是将标签添加到帖子还是将帖子添加到标签?在这个例子中,我用这些标签创建了一个帖子,所以我假设只对帖子添加标签……不管你用哪种方式做,只做一个。我会在新帖子上设置标签,但无论如何都不会删除错误。该行为表明,它可能会用一个新名称(“两个”)覆盖数据库中的原始标记。我意识到,如果我在第二篇文章中使用“二”而不是“一”,“二”,这个问题就不会出现……我错了。删除数据库并进行更改确实解决了这个问题—您是说indexPath!而不是IndexPath?这个问题已经解决了,这个改变,以及您关于只将标签添加到帖子中,而不将帖子添加到标签中的建议。
Insert Object: Optional([0, 0])
Insert Object: Optional([0, 0])
2018-12-05 12:51:16.947569-0800 SweatNetOffline[71327:19904799] *** Assertion failure in -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKitCore_Sim/UIKit-3698.84.15/UICollectionView.m:5908
2018-12-05 12:51:16.949957-0800 SweatNetOffline[71327:19904799] [error] fault: Serious application error.  An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:.  attempt to delete item 1 from section 0 which only contains 1 items before the update with userInfo (null)
 case .update:
     blockOperations.append(
         BlockOperation(block: { [weak self] in
             if let this = self {
                 this.latestTagsCollectionView!.reloadItems(at: [indexPath!])
             }
         })
     )