0

I am trying to convert a working table view to a table view making use of NSFetchedResultsController.

I am testing with just two entries and this is part of my working code

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
let fetchRequest = NSFetchRequest(entityName: "Appointments")
        //3
        do {
            self.tableView.reloadData()
            let results = try context.executeFetchRequest(fetchRequest)
            invoices = results as Array<AnyObject>  //cast to Appointments didn't work           
        } catch let error as NSError {
            print("Could not fetch \(error), \(error.userInfo)")
        }

And this is part of my converting code

    let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext

var frc: NSFetchedResultsController = NSFetchedResultsController()

func getFetchedResultsController()->NSFetchedResultsController {
    frc = NSFetchedResultsController(fetchRequest: listFetchRequest(), managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
    return frc
}

func listFetchRequest()->NSFetchRequest{
    let fetchRequest = NSFetchRequest(entityName: "Appointments")
    let sortDescriptor = NSSortDescriptor(key: "appointmentUser", ascending: true)
    fetchRequest.sortDescriptors = [sortDescriptor]
    return fetchRequest
}

var appointments = [AnyObject]()//[NSManagedObject]()

It builds successfull, but i am directly getting an error message: fatal error: unexpectedly found nil while unwrapping an Optional value

libswiftCore.dylib`function signature specialization <Arg[0] = Exploded, Arg[1] = Exploded, Arg[2] = Dead, Arg[3] = Dead> of Swift._fatalErrorMessage (Swift.StaticString, Swift.StaticString, Swift.StaticString, Swift.UInt) -> ():
0x1002c0a50 <+0>:   stp    x29, x30, [sp, #-16]!
0x1002c0a54 <+4>:   mov    x29, sp
0x1002c0a58 <+8>:   sub    sp, sp, #16
0x1002c0a5c <+12>:  and    w8, w2, #0x1
0x1002c0a60 <+16>:  tbnz   w8, #0, 0x1002c0a80       ; <+48>
0x1002c0a64 <+20>:  tbnz   x1, #63, 0x1002c0ac4      ; <+116>
0x1002c0a68 <+24>:  add    x1, x0, x1
0x1002c0a6c <+28>:  mov    x2, x3
0x1002c0a70 <+32>:  mov    x3, x4
    0x1002c0a74 <+36>:  mov    x4, x5
    0x1002c0a78 <+40>:  bl     0x10030d910               ; function signature specialization <Arg[0] = Exploded, Arg[1] = Exploded> of Swift.(_fatalErrorMessage (Swift.StaticString, Swift.StaticString, Swift.StaticString, Swift.UInt) -> ()).(closure #2)
->  0x1002c0a7c <+44>:  brk    #0x1
    0x1002c0a80 <+48>:  str    xzr, [sp, #8]
    0x1002c0a84 <+52>:  cmp    x0, w0, uxtw

How can i check where the unwrapping occurs? How can i fix this?

[EDIT] With some trial and error (outcommenting parts) i think it has to do with this part of my code

        override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
//        return 1
        let numberOfSections = frc.sections?.count
        return numberOfSections!
    }

see also: NSFetchedResultsController swift sections

Community
  • 1
  • 1
alex
  • 4,804
  • 14
  • 51
  • 86
  • Why do you declare `invoices` as `[AnyObject]` although it's doubtless `[NSManagedObject]`. The more specific the code is designed the less compiler errors/warnings and even crashes you get. -- `invoices = try context.executeFetchRequest(fetchRequest) as! [NSManagedObject]`. If any error occurs it will be caught properly. – vadian Oct 22 '15 at 11:56
  • if i am casting to Appointments i am getting fatal error: NSArray element failed to match the Swift Array Element type – alex Oct 22 '15 at 12:13
  • Ok i had to add class id in model file as well see http://stackoverflow.com/questions/31304638/fetchrequest-nsarray-element-failed-to-match-the-swift-array-element-type-sw but still frc is not working as expected – alex Oct 22 '15 at 12:23

1 Answers1

1

The problem is with this piece of code:

// issue 1
var frc: NSFetchedResultsController = NSFetchedResultsController()

// issue 2
func getFetchedResultsController()->NSFetchedResultsController {
    frc = NSFetchedResultsController(fetchRequest: listFetchRequest(), managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
    return frc
}

Issue 1: NSFetchedResultsController is being instantiated (but not configured) and stored in frc.

Issue 2: The function creates a new, configured, NSFetchedResultsController (and stores it in frc) every time it is called.

I think what you were trying to achieve here is lazy instantiation, remove the getFetchedResultsController function and replace the variable declaration with this:

lazy var frc: NSFetchedResultsController = {
    let fetchedResultsController = NSFetchedResultsController(fetchRequest: self.listFetchRequest(), managedObjectContext: self.context, sectionNameKeyPath: nil, cacheName: nil)
    fetchedResultsController.delegate = self
    return fetchedResultsController
}()

This will setup the fetched results controller when the frc property is first accessed and assign the delegate as self.

Based on your comments the viewDidLoad method will look something like this:

override func viewDidLoad() {
    super.viewDidLoad()

    do {
        try self.frc.performFetch()
    } catch {
        ...
    }
}
Steve Wilford
  • 8,894
  • 5
  • 42
  • 66
  • hmmm, i am getting an error message "Missing argument for parameter #1 in call" when i use your lazy instantiation – alex Oct 22 '15 at 11:32
  • 1
    @alex I've updated my answer, it needs to reference `self` – Steve Wilford Oct 22 '15 at 12:38
  • your new function does built but didn't fix my problem. I had to replace this code ` frc = getFetchedResultsController() frc.delegate = self do { try frc.performFetch() } catch { print(error) }` to viewDidLoad . I had the code in viewDidAppear – alex Oct 22 '15 at 12:44
  • 1
    @alex You don't need the `getFetchedResultsController` function, I'll update my answer again... – Steve Wilford Oct 22 '15 at 12:47