Bartłomiej Semańczyk Bartłomiej Semańczyk - 6 months ago 20
Swift Question

Swift: NSArrayM controllerWillChangeContent:]: unrecognized selector sent to instance

In my controller I have two

UICollectionView
's with two different
NSFetchedResultsControllers
:

This is how I create it in
viewDidLoad:
:

private func setupFetchedResultsControllers() {

let currentStudent = BWSettings.sharedSettings.currentUser as! BWCoreDataStudent
let context = NSManagedObjectContext.MR_defaultContext()

let topFetchReguest = NSFetchRequest(entityName: "BWCoreDataWishlistBook")
let positionDescriptor = NSSortDescriptor(key: "position", ascending: true)

topFetchReguest.sortDescriptors = [positionDescriptor]

topFetchedResultsController = NSFetchedResultsController(fetchRequest: topFetchReguest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
topFetchedResultsController.fetchRequest.predicate = NSPredicate(format: "student.id = %lld AND position != nil", currentStudent.id)
topFetchedResultsController.delegate = BWStudentWishlistFetchedResultsControllerDelegate(collectionView: topCollectionView, studentWishlistContainerViewController: self)

try! topFetchedResultsController.performFetch()

let bottomFetchReguest = NSFetchRequest(entityName: "BWCoreDataWishlistBook")
let addedAtDescriptor = NSSortDescriptor(key: "createdAt", ascending: true)

bottomFetchReguest.sortDescriptors = [addedAtDescriptor]

bottomFetchedResultsController = NSFetchedResultsController(fetchRequest: bottomFetchReguest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
bottomFetchedResultsController.fetchRequest.predicate = NSPredicate(format: "student.id = %lld AND position = nil", currentStudent.id)
bottomFetchedResultsController.delegate = BWStudentWishlistFetchedResultsControllerDelegate(collectionView: bottomCollectionView, studentWishlistContainerViewController: self)

try! bottomFetchedResultsController.performFetch()
}


And this is my custom delegate:

class BWStudentWishlistFetchedResultsControllerDelegate: NSObject, NSFetchedResultsControllerDelegate {

private var collectionView: UICollectionView!
private var collectionViewChanges = [[NSFetchedResultsChangeType: [NSIndexPath]]]()

private weak var studentWishlistContainerViewController: BWStudentWishlistContainerViewController!

init(collectionView: UICollectionView, studentWishlistContainerViewController: BWStudentWishlistContainerViewController) {

self.collectionView = collectionView
self.studentWishlistContainerViewController = studentWishlistContainerViewController
}

//MARK: - NSFetchedResultsControllerDelegate
//here are my custom default methods
}


This is a whole error message:


*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM controllerWillChangeContent:]: unrecognized selector sent to instance 0x14ec0d930'


Why it happens?

Answer

Your error is that your NSFetchedResultsController delegate is deallocating. Instead of :

 topFetchedResultsController.delegate = BWStudentWishlistFetchedResultsControllerDelegate(collectionView: topCollectionView, studentWishlistContainerViewController: self)

You need to keep a reference to the delegate using a property :

var fetchDelegate = BWStudentWishlistFetchedResultsControllerDelegate(..)
...
topFetchedResultsController.delegate = self.fetchDelegate

With your way of doing this the delegate is released at the end of setupFetchedResultsControllers() scope

Comments