Проблемы с NSFetchedResultsController, UICollectionView и BlockOperations

Я использую Flickr API загружать изображения, определенные для местоположения булавки, сброшенного пользователем. Я хочу, чтобы была возможность получить новый набор изображений, над которыми я сейчас работаю. Проблема в том, что это работает только один раз.

import UIKit
import CoreData
import MapKit

class PhotoCollectionViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, 

NSFetchedResultsControllerDelegate {

@IBOutlet weak var mapView:MKMapView!
@IBOutlet weak var photoCollectionView:UICollectionView!
@IBOutlet weak var backButton: UIBarButtonItem!
@IBOutlet weak var deleteButton: UIBarButtonItem!
@IBOutlet weak var noPhotosView: UIView!

var pinID = NSManagedObjectID()
var noPhotosBool = Bool()
var fetchedResults = [Photo]()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var shouldReloadCollectionView = true
var deletedIndexes = [IndexPath]()
var blockOperations = [BlockOperation]()
var deleteAllBool = Bool()


var fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult>? {
    didSet{
        fetchedResultsController?.delegate = self
        fetchResults()
        self.photoCollectionView.reloadData()
    }
}

override func viewDidLoad() {
    noPhotosView.isHidden = true
    super.viewDidLoad()
    //photoCollectionView.setCollectionViewLayout(photoCollectionViewFlowLayout, animated: true)
    var currentPin: Pin!
    let fetchPin = NSFetchRequest<Pin>(entityName: "Pin")
    let fetchedPins = try! context.fetch(fetchPin)
    for pin in fetchedPins {
        if pin.objectID == FlickrClient.Constants.Flickr.currentPinObjectID {
            currentPin = pin
        }
    }
    print(currentPin.latitude, currentPin.longitude)

    let photoRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Photo")
    let photoPredicate = NSPredicate(format: "pin = %@", currentPin)
    let sort = NSSortDescriptor(key: "id", ascending: false)
    photoRequest.sortDescriptors = [sort]
    photoRequest.predicate = photoPredicate
    fetchedResults = try! context.fetch(photoRequest) as! [Photo]
    photoCollectionView?.delegate = self
    photoCollectionView?.dataSource = self
    let frc = NSFetchedResultsController(fetchRequest: photoRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
    fetchedResultsController = frc


    // Map Setup
    self.mapView?.camera.altitude = CLLocationDistance(12000)
    self.mapView?.centerCoordinate = CLLocationCoordinate2D(latitude: CLLocationDegrees(currentPin.latitude), longitude: CLLocationDegrees(currentPin.longitude))
    let currentPinAnnotation = MKPointAnnotation()
    currentPinAnnotation.coordinate.latitude = CLLocationDegrees(currentPin.latitude)
    currentPinAnnotation.coordinate.longitude = CLLocationDegrees(currentPin.longitude)
    self.mapView?.addAnnotation(currentPinAnnotation)
}

func fetchResults() {
    if let fc = fetchedResultsController {
        do {
            try fc.performFetch()
        }catch {
            print(error)
        }
    }
}
required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

@IBAction func dismissPhotoCollectionViewController(_ sender: Any) {
    self.dismiss(animated: true) {
        FlickrClient.Constants.Flickr.currentPinObjectID = nil
    }
}

@IBAction func deletePhotos(_ sender: Any) {
    var deletePhotos = [Photo]()
    deleteAllBool = true
    shouldReloadCollectionView = false
    var indexsToDelete = [IndexPath]()
    for section in 0..<photoCollectionView.numberOfSections {
        for index in 0..<photoCollectionView.numberOfItems(inSection: section) {
            indexsToDelete.append(IndexPath(item: index, section: section))
        }
    }

    print(indexsToDelete.count)
    print(fetchedResultsController?.fetchedObjects?.count)

    for index in indexsToDelete {
        deletePhotos.append(fetchedResultsController?.object(at: index) as! Photo)
    }
    for photo in deletePhotos {
        fetchedResultsController?.managedObjectContext.delete(photo)
    }
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let photo = fetchedResultsController?.object(at: indexPath)
    fetchedResultsController?.managedObjectContext.delete(photo as! Photo)
}

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
}

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    if type == .insert {
        print("insert@\(indexPath)")
        if (photoCollectionView.numberOfSections) > 0 {
            if photoCollectionView.numberOfItems(inSection: newIndexPath!.section) == 0 {
                self.shouldReloadCollectionView = true
            }else {
                if deleteAllBool == true {
                    blockOperations.append(
                        BlockOperation(block: { [weak self] in
                            if let this = self {
                                this.photoCollectionView.insertItems(at: [newIndexPath!])
                            }

                        })
                    )
                }else {
                    self.photoCollectionView.insertItems(at: [newIndexPath!])
                }
            }
        } else {
            self.shouldReloadCollectionView = true
        }

    }
    else if type == .move {
        print("moveItem@\(indexPath)")
        //blockOperations.append(BlockOperation(block: { [weak self] in
        //  if let this = self {
        //    DispatchQueue.main.async {
        self.photoCollectionView.moveItem(at: indexPath!, to: newIndexPath!)
        // }
        //}

        //}))
    }
    else if type == .update {
        print("updateItem@\(indexPath)")
        //blockOperations.append(BlockOperation(block: { [weak self] in
        //  if let this = self {
        //    DispatchQueue.main.async {
        self.photoCollectionView.reloadItems(at: [indexPath!])
        //}
        //}

        //}))
    }
    else if type == .delete {
        print("deleteItem@\(indexPath)")
        // shouldReloadCollectionView = false
        if photoCollectionView.numberOfItems(inSection: (indexPath?.section)!) == 1 {
            self.shouldReloadCollectionView = true
        }else {
            if deleteAllBool == true {
                blockOperations.append(BlockOperation(block: { [weak self] in
                    if let this = self {
                        //DispatchQueue.main.async {
                        this.photoCollectionView.deleteItems(at: [indexPath!])
                        //}
                    }
                }))
            }else {
                self.photoCollectionView.deleteItems(at: [indexPath!])

            }
        }
    }
}

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
    if type == .insert {
        //blockOperations.append(BlockOperation(block: { [weak self] in
        // if let this = self {
        //   DispatchQueue.main.async {
        self.photoCollectionView.insertSections(NSIndexSet(index: sectionIndex) as IndexSet)
        // }
        //}
        //}))
    }
    else if type == .update {
        //            blockOperations.append(BlockOperation(block: { [weak self] in
        //                if let this  = self {
        //                    DispatchQueue.main.async {
        self.photoCollectionView.reloadSections(NSIndexSet(index: sectionIndex) as IndexSet)
        //                    }
        //                }
        //            }))
    }
    else if type == .delete {
        //            blockOperations.append(BlockOperation(block: { [weak self] in
        //                if let this = self {
        //DispatchQueue.main.async {
        self.photoCollectionView.deleteSections(NSIndexSet(index: sectionIndex)as IndexSet)
        //}
        //                }
        //            }))
    }
}


func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    print("controller Did Change Content", self.shouldReloadCollectionView)
    // self.shouldReloadCollectionView = false

    if self.shouldReloadCollectionView == true {
        //DispatchQueue.main.async {
        self.photoCollectionView.reloadData()
        //}
    }else {
        self.photoCollectionView.performBatchUpdates({ () -> Void in
            for operation: BlockOperation in self.blockOperations {
                operation.start()
            }
        }, completion: {(finished) -> Void in
            self.shouldReloadCollectionView = true
            self.blockOperations.removeAll(keepingCapacity: false)
            if self.photoCollectionView.numberOfItems(inSection: 0) < 1 {
                FlickrClient.sharedInstance().getPhotosFromFlickr(lat: Float(self.mapView.annotations[0].coordinate.latitude), lon: Float(self.mapView.annotations[0].coordinate.longitude)) { (success, error) in
                    if success != true {
                        print(error)
                    }else {
                        //try! self.fetchedResultsController?.performFetch()
                        //self.photoCollectionView.reloadData()
                    }
                }
            }
        })
    }
}

func numberOfSections(in collectionView: UICollectionView) -> Int {
    return (fetchedResultsController?.sections?.count)!
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    let sectionData = fetchedResultsController?.sections![section]
    return (sectionData?.numberOfObjects)!
}

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    let reuseId = "pin"
    var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
    if pinView == nil {
        pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
        pinView!.canShowCallout = true
        pinView!.pinTintColor = .red
        pinView!.animatesDrop = true
        pinView!.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
        pinView!.rightCalloutAccessoryView?.backgroundColor = UIColor.cyan
    }
    else {
        pinView!.annotation = annotation
    }
    return pinView
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = photoCollectionView?.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! photoCollectionViewCell
    cell.photoActivityIndicator.isHidden = false
    cell.photoActivityIndicator.startAnimating()
    cell.photoActivityIndicator.hidesWhenStopped = true
    cell.photoImageView.image = #imageLiteral(resourceName: "placeholder")

    let photo = fetchedResultsController?.object(at: indexPath) as! Photo

    if photo.imageData != nil {
        cell.photoImageView.image = UIImage(data: photo.imageData! as Data)
        cell.photoActivityIndicator.stopAnimating()

    }else {
        DispatchQueue.main.async {
            let session = URLSession.shared
            let request = URLRequest(url: URL(string: photo.imageURL!)!)
            let task = session.dataTask(with: request) { (data, response, error) in
                if error != nil {
                    print(error)
                }else {
                    photo.imageData = data! as NSData
                    cell.photoImageView.image = UIImage(data: photo.imageData! as Data)
                    cell.photoActivityIndicator.stopAnimating()
                }
            }
            task.resume()
        }
    }
    return cell
}

}

Выше мой код для collectionViewController и соответствующий NSFetchedResultsController, Моя проблема в первый раз IBActiondeletePhotos() называется, все работает отлично. Фотографии удалены из CoreDataэто вызывает NSFetchedResultsController реализовать изменения в collectionView, а затем сделать еще один звонок Flickr чтобы получить другой набор изображений, связанных с местоположением этого вывода. Второй раз IBAction называется, фотографии удаляются из CoreData, но NSFetchedResultsController"s didChangeContent не звонит Flickr, Итак, мой вопрос, что отличается между первым удалением и вторым, что делает его таким NSFetchedResultsController не будет звонить Flickr?

0 ответов

Другие вопросы по тегам