Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/358.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 在后台上下文中保存NSManagedObjects时出现问题_Ios_Swift_Multithreading_Core Data_Data Persistence - Fatal编程技术网

Ios 在后台上下文中保存NSManagedObjects时出现问题

Ios 在后台上下文中保存NSManagedObjects时出现问题,ios,swift,multithreading,core-data,data-persistence,Ios,Swift,Multithreading,Core Data,Data Persistence,我已经为此挣扎了好几天了。我将感谢任何帮助 我有一个位置NSManagedObject和一个图像NSManagedObject,它们有一对多关系,即一个位置有多个图像 我有两个屏幕,在第一个屏幕中,用户在视图上下文中添加位置,添加和检索位置时不会出现问题 现在,在第二个屏幕中,我想根据在第一个屏幕中选择的位置检索图像,然后在集合视图中显示图像。图像首先从flickr检索,然后保存在数据库中 我想在背景环境中保存和检索图像,这给我带来了很多问题 当我试图保存从flickr检索到的每个图像时,我会收

我已经为此挣扎了好几天了。我将感谢任何帮助

我有一个位置
NSManagedObject
和一个图像
NSManagedObject
,它们有一对多关系,即一个位置有多个图像

我有两个屏幕,在第一个屏幕中,用户在视图上下文中添加位置,添加和检索位置时不会出现问题

现在,在第二个屏幕中,我想根据在第一个屏幕中选择的位置检索图像,然后在集合视图中显示图像。图像首先从flickr检索,然后保存在数据库中

我想在背景环境中保存和检索图像,这给我带来了很多问题

  • 当我试图保存从flickr检索到的每个图像时,我会收到一条警告,指出存在悬空对象,并且关系无法建立:
  • 这是我的保存代码:

      func saveImagesToDb () {
    
            //Store the image in the DB along with its location on the background thread
            if (doesImageExist()){
                dataController.backgroundContext.perform {
    
                    for downloadedImage in self.downloadedImages {
                        print ("saving to context")
                        let imageOnMainContext = Image (context: self.dataController.viewContext)
                        let imageManagedObjectId = imageOnMainContext.objectID
                        let imageOnBackgroundContext = self.dataController.backgroundContext.object(with: imageManagedObjectId) as! Image
    
                        let locationObjectId = self.imagesLocation.objectID
                        let locationOnBackgroundContext = self.dataController.backgroundContext.object(with: locationObjectId) as! Location
    
                        let imageData = NSData (data: downloadedImage.jpegData(compressionQuality: 0.5)!)
                        imageOnBackgroundContext.image = imageData as Data
                        imageOnBackgroundContext.location = locationOnBackgroundContext
    
    
                        try? self.dataController.backgroundContext.save ()
                    }
                }
            }
        }
    
    正如您在上面的代码中所看到的,我正在基于从视图上下文中检索到的ID在后台上下文中构建NSManagedObject。每次调用
    saveImagesToDb
    时,我都会收到警告,那么问题出在哪里

  • 尽管有上述警告,当我通过FetchedResultsController(在后台上下文中工作)检索数据时。“集合”视图有时可以很好地查看图像,有时会出现以下错误:
  • 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无效更新:节0中的项目数无效。”。更新(4)后包含在现有节中的项目数必须等于更新(1)前包含在该节中的项目数,加上或减去从该节插入或删除的项目数(1插入,0删除),加上或减去移入或移出该节的项目数(0移入,0移出)。
    '

    以下是一些与设置FetchedResultsController和基于上下文或FetchedResultsController中的更改更新集合视图相关的代码片段

      func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    
            guard let imagesCount = fetchedResultsController.fetchedObjects?.count else {return 0}
    
            return imagesCount
        }
    
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            print ("cell data")
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoCell", for: indexPath) as! ImageCell
            //cell.placeImage.image = UIImage (named: "placeholder")
    
            let imageObject = fetchedResultsController.object(at: indexPath)
            let imageData = imageObject.image
            let uiImage = UIImage (data: imageData!)
    
            cell.placeImage.image = uiImage
            return cell
        }
    
    
    
    func setUpFetchedResultsController () {
            print ("setting up controller")
            //Build a request for the Image ManagedObject
            let fetchRequest : NSFetchRequest <Image> = Image.fetchRequest()
            //Fetch the images only related to the images location
    
            let locationObjectId = self.imagesLocation.objectID
            let locationOnBackgroundContext = self.dataController.backgroundContext.object(with: locationObjectId) as! Location
            let predicate = NSPredicate (format: "location == %@", locationOnBackgroundContext)
    
            fetchRequest.predicate = predicate
            fetchRequest.sortDescriptors = [NSSortDescriptor(key: "location", ascending: true)]
    
            fetchedResultsController = NSFetchedResultsController (fetchRequest: fetchRequest, managedObjectContext: dataController.backgroundContext, sectionNameKeyPath: nil, cacheName: "\(latLongString) images")
    
            fetchedResultsController.delegate = self
    
            do {
                try fetchedResultsController.performFetch ()
            } catch {
                fatalError("couldn't retrive images for the selected location")
            }
        }
    
        func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    
            print ("object info changed in fecthed controller")
    
            switch type {
            case .insert:
                print ("insert")
                DispatchQueue.main.async {
                    print ("calling section items")
                    self.collectionView!.numberOfItems(inSection: 0)
                    self.collectionView.insertItems(at: [newIndexPath!])
                }
                break
    
            case .delete:
                print ("delete")
    
                DispatchQueue.main.async {
                    self.collectionView!.numberOfItems(inSection: 0)
                    self.collectionView.deleteItems(at: [indexPath!])
                }
                break
            case .update:
                print ("update")
    
                DispatchQueue.main.async {
                    self.collectionView!.numberOfItems(inSection: 0)
                    self.collectionView.reloadItems(at: [indexPath!])
                }
                break
            case .move:
                print ("move")
    
                DispatchQueue.main.async {
                    self.collectionView!.numberOfItems(inSection: 0)
                    self.collectionView.moveItem(at: indexPath!, to: newIndexPath!)
    
                }
    
            }
        }
    
        func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
            print ("section info changed in fecthed controller")
            let indexSet = IndexSet(integer: sectionIndex)
            switch type {
            case .insert:
                self.collectionView!.numberOfItems(inSection: 0)
                collectionView.insertSections(indexSet)
                break
            case .delete:
                self.collectionView!.numberOfItems(inSection: 0)
                collectionView.deleteSections(indexSet)
            case .update, .move:
                fatalError("Invalid change type in controller(_:didChange:atSectionIndex:for:). Only .insert or .delete should be possible.")
            }
    
        }
    
        func addSaveNotificationObserver() {
            removeSaveNotificationObserver()
            print ("context onbserver notified")
            saveObserverToken = NotificationCenter.default.addObserver(forName: .NSManagedObjectContextObjectsDidChange, object: dataController?.backgroundContext, queue: nil, using: handleSaveNotification(notification:))
        }
    
        func removeSaveNotificationObserver() {
            if let token = saveObserverToken {
                NotificationCenter.default.removeObserver(token)
            }
        }
    
        func handleSaveNotification(notification:Notification) {
            DispatchQueue.main.async {
                self.collectionView!.numberOfItems(inSection: 0)
                self.collectionView.reloadData()
            }
        }
    
    func collectionView(collectionView:UICollectionView,numberofitemsinssection:Int)->Int{
    guard let ImageScont=fetchedResultsController.FetchedObject?.count else{return 0}
    返回图像搜索
    }
    func collectionView(collectionView:UICollectionView,cellForItemAt indexPath:indexPath)->UICollectionViewCell{
    打印(“单元数据”)
    让cell=collectionView.dequeueReusableCell(带有reuseidentifier:“photoCell”,for:indexPath)作为!ImageCell
    //cell.placeImage.image=UIImage(名为“占位符”)
    让imageObject=fetchedResultsController.object(位于:indexPath)
    让imageData=imageObject.image
    让uiImage=uiImage(数据:imageData!)
    cell.placeImage.image=uiImage
    返回单元
    }
    func setUpFetchedResultsController(){
    打印(“设置控制器”)
    //为映像ManagedObject生成请求
    let fetchRequest:NSFetchRequest=Image.fetchRequest()
    //获取仅与图像位置相关的图像
    让locationObjectId=self.imagesLocation.objectID
    让locationOnBackgroundContext=self.dataController.backgroundContext.object(带有:locationObjectId)作为!位置
    let谓词=NSPredicate(格式:“位置==%@”,locationOnBackgroundContext)
    fetchRequest.predicate=谓词
    fetchRequest.sortDescriptors=[NSSortDescriptor(键:“位置”,升序:true)]
    fetchedResultsController=NSFetchedResultsController(fetchRequest:fetchRequest,managedObjectContext:dataController.backgroundContext,sectionNameKeyPath:nil,cacheName:“\(latLongString)图像”)
    fetchedResultsController.delegate=self
    做{
    请尝试fetchedResultsController.performFetch()
    }抓住{
    fatalError(“无法检索所选位置的图像”)
    }
    }
    func控制器(controller:NSFetchedResultsController,didChange anObject:Any,在indexPath:indexPath?处,对于类型:NSFetchedResultsChangeType,newIndexPath:indexPath?){
    打印(“对象信息在fecthed控制器中更改”)
    开关类型{
    案例.插入:
    打印(“插入”)
    DispatchQueue.main.async{
    打印(“调用节项”)
    self.collectionView!.numberOfItems(第0节)
    self.collectionView.insertItems(位于:[newIndexPath!]
    }
    打破
    案例.删除:
    打印(“删除”)
    DispatchQueue.main.async{
    self.collectionView!.numberOfItems(第0节)
    self.collectionView.deleteItems(位于:[indexPath!))
    }
    打破
    案例。更新:
    打印(“更新”)
    DispatchQueue.main.async{
    self.collectionView!.numberOfItems(第0节)
    self.collectionView.reloadeItems(位于:[indexPath!))
    }
    打破
    案件.动议:
    打印(“移动”)
    DispatchQueue.main.async{
    self.collectionView!.numberOfItems(第0节)
    self.collectionView.moveItem(位于:indepath!,至:newindepath!)
    }
    }
    }
    func控制器(控制器:NSFetchedResultsController,didChange sectionInfo:NSFetchedResultsSectionInfo,atSectionIndex sectionIndex:Int,类型:NSFetchedResultsChangeType){
    打印(“在fecthed控制器中更改的节信息”)
    让indexSet=indexSet(整数:sectionIndex)
    开关类型{
    案例.插入:
    self.collectionView!.numberOfItems(第0节)
    collectionView.insertSections(indexSet)
    打破
    案例.删除:
    self.collectionView!.numberOfItems(第0节)
    collectionView.deleteSecti
    
    guard let imagesCount = fetchedResultsController.fetchedObjects?.count else {return 0}
    
     DispatchQueue.main.async {
                print ("calling section items")
                self.collectionView!.numberOfItems(inSection: 0)
                self.collectionView.insertItems(at: [newIndexPath!])
            }
    
    func controllerWillChangeContent(_ controller: 
    
        NSFetchedResultsController<NSFetchRequestResult>) {
                DispatchQueue.main.async {
                    self.collectionView.reloadData()
                }
            }
    
    func saveImagesToDb () {
    
            //Store the image in the DB along with its location on the background thread
            dataController.backgroundContext.perform {
                for downloadedImage in self.downloadedImages {
                    let imageOnBackgroundContext = Image (context: self.dataController.backgroundContext)
    
                    //imagesLocation is on the view context
                    let locationObjectId = self.imagesLocation.objectID
                    let locationOnBackgroundContext = self.dataController.backgroundContext.object(with: locationObjectId) as! Location
    
                    let imageData = NSData (data: downloadedImage.jpegData(compressionQuality: 0.5)!)
                    imageOnBackgroundContext.image = imageData as Data
                    imageOnBackgroundContext.location = locationOnBackgroundContext
    
    
                    guard (try? self.dataController.backgroundContext.save ()) != nil else {
                        self.showAlert("Saving Error", "Couldn't store images in Database")
                        return
                    }
                }
            }
    
        }