Search code examples
core-datansfetchrequestswift3

Swift 3 Fetch Request Error (warning: could not load any Objective-C class information)


I recently received this error when fetching data from Core Data:

warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available. (lldb)

Here is my code:

// MARK: - Initialize Fetch Request

var fetchedResultsController = NSFetchedResultsController<Profile>()

func setFetchRequest() -> NSFetchRequest<Profile> {

    let request = Profile.fetchRequest()
    let sortDescriptor = SortDescriptor(key: "title", ascending: false)

        do {
            try moc?.fetch(request)
        } catch {
            print("Error With Request: \(error)")
        }
        request.sortDescriptors = [sortDescriptor]

    return setFetchRequest()
}


// MARK: - Retrieve Fetch Request

func getFetchRequest() -> NSFetchedResultsController<Profile> {

    fetchedResultsController = NSFetchedResultsController(fetchRequest: setFetchRequest(), managedObjectContext: moc!, sectionNameKeyPath: nil, cacheName: nil)

    return fetchedResultsController
}

I crashed with this error where I have "try moc?.fetch(request)":

Thread 1 EXC_BAD_ACCESS (code=2, address=0x16fc07feo)

Are these errors connected or is this a bug in Swift 3 / Xcode 8?


Solution

  • You shouldn't take results from the ManagedObjectContext. If you want to use a NSFetchedResultsController class in your app? You'll need to access their methods. And all of the required or optional methods are comes from the NSFetchedResultsControllerDelegate protocol.

    Try this

    class YourTableViewController: UITableViewController, NSFetchedResultsControllerDelegate { var fetchedResultsController:NSFetchedResultsController<Profile>! }

    And then create a custom helper function like this one:

    `func frc() {

        let request:NSFetchRequest<Profile> = Profile.fetchRequest()
        let sorter = SortDescriptor(key: "title", ascending: true)
        request.sortDescriptors = [sorter]
    
        self.fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
        // make sure the delegate is set to self
        self.fetchedResultsController.delegate = self
    
        do {
         try self.fetchedResultsController.performFetch()
        } catch {} 
    }
    

    `

    From this point you'll need a trigger to perform operations. So let's the system itself should be doing this when you call the viewDidLoad method or you can create a button instead. For example click the button to begin operations.

    override func viewDidLoad() { super.viewDidLoad() self.frc() self.tableView.reloadData() }

    It should be works. Good luck!

    Automatic Subclass Generation

    Xcode 8 and Swift 3 comes with a new generation of subclassing called as Automatic Subclass Generation! How to create it? Well! So let's create a new Xcode 8 project, choose a Single View Application and then another window will appears called Choose options for your new project:. Give the name for your new project, make sure language is a Swift and Use Core Data check box is checked and then hit Create.

    Go to the YourProjectName.xcdatamodeld file and click it. And then add an entity! So let's say your entity name is a Profile and create their Attributes respectively. It's important to know, because this is an Automatic Subclass Generation. Choose your entity and go to the Data Model Inspector ! Choose a Class Definition for the Codegen You can find a Codegen from here.

    After selected the Class Definition, you can see Name text field automatically filled by your entity name like so. Again go to the your entity and click it. Click Command + S for save changes firstly and then click Command + B for rebuild, that's it. Automatic Subclass Generation is successfully created.

    Remember

    If you want to change your model? For example: If you want to add a new Attribute to your model? It's very easy, select a xcdatamodeld file and click your entity. Click the plus sign under Attributes and add your new Attribute. After your changes is completed? Don't forget to save changes. Again click Command + S and then click Command + B

    Create A Managed Object

    In the Swift 3 you can create a ManagedObject by using subclass initializer. It's very easy to implementing than ever before

    let managedObject = Profile(context: self.managedObjectContext!)

    You can see it's very easy! How to save values to the managedObject ? So let's say you have a title attribute of your model. Also title is a String.

    managedObject.setValue("Well crafted API? Right?", forKey: "title")

    or

    managedObject.title = "Well crafted API? Right?"

    Save values:

    do { try self.managedObjectContext.save() print(managedObject) } catch {}

    It's works well on the Swift 3.0 beta and Xcode 8.0 beta.