How to use predicates with fetchRequest in Core Data

vrao picture vrao · Jan 13, 2017 · Viewed 28.2k times · Source

I pass a contact Identifier from Contacts tableview controller to another Location tableview controller. So I define a delegate ContactSelectionDelegate and implement method userSelectedContact in Location tableview controller and get contactIdentifierString

I am searching the database to find a match for contactIdentifierString and find value for another attribute provider name. This involves searching the whole database. Is there a faster way by assigning a predicate to the context fetchRequest. I thought that would be faster and fewer lines of code.

Can someone suggest how to use predicates with contact fetchRequest?

ContactTableViewController code:

protocol ContactSelectionDelegate{
func userSelectedContact(contactIdentifier:NSString)
}

class ContactTableViewController: UITableViewController {

var delegate:ContactSelectionDelegate? = nil

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    if (delegate != nil){
        let contactDict:NSDictionary = allContacts.object(at: indexPath.row) as! NSDictionary
        let identifier = contactDict.object(forKey: "uniqueId")
                   delegate!.userSelectedContact(contactIdentifier: identifier as! NSString)
                  self.navigationController!.popViewController(animated: true)
               }
}

}

LocationTableViewController code:

 class LocationTableViewController: UITableViewController, ContactSelectionDelegate, CLLocationManagerDelegate {

var contactIdentifierString:NSString = NSString()

 func userSelectedContact(contactIdentifier: NSString) {
    var fetchedResults: [Contact] = []

    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

    do {
        fetchedResults = try context.fetch(Contact.fetchRequest())
    }
    catch {
        print ("fetch task failed")
    }
    if fetchedResults.count > 0 {
        for contact in fetchedResults{
            let aContact:Contact = contact
            if (aContact.uniqueId! == contactIdentifierString as String) {
                providerName.text = aContact.providerName
            }
            else {
                continue
            }
        }
    }


}

Answer

vadian picture vadian · Jan 13, 2017

First of all get rid of all NSString and NSDictionary occurrences. This is Swift!. Use the Swift native structs String and Dictionary.

Second of all put always all good code in the do scope of a do - catch block.

A CoreData predicate has a simple format attribute == value which is very similar to aContact.uniqueId! == contactIdentifierString:

var contactIdentifierString = ""

func userSelectedContact(contactIdentifier: String) {

    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

    do {
        let fetchRequest : NSFetchRequest<Contact> = Contact.fetchRequest()
        fetchRequest.predicate = NSPredicate(format: "uniqueId == %@", contactIdentifier)
        let fetchedResults = try context.fetch(fetchRequest)
        if let aContact = fetchedResults.first {
           providerName.text = aContact.providerName
        }
    }
    catch {
        print ("fetch task failed", error)
    }

}

The code assumes that there is a NSManagedObject subclass Contact containing

@nonobjc public class func fetchRequest() -> NSFetchRequest<Contact> {
    return NSFetchRequest<Contact>(entityName: "Contact")
}