Implement a search similar to that of native contacts?

In the native contacts app, when you try to find contacts, you enter some string and if the first and last name of the contact person / company, etc. start with this line, the contact will be displayed.

To make things more complicated, you can type something like Mi Ric and a search will find Michael Richardson. Also Rick Mee will get me Michael Richardson.

I made a copy of the contact entry in my local kernel datastore and now my first instinct is to use NSFetchedResultsController

some good predicate as well.

But how would I go about this predicate? If a person's entry has up to 3 words, should I query each word with beginWith? Can even one predicate do this?

+3


source to share


2 answers


This is what I use for the word base predicate:

+ (NSPredicate *)wordBasedPredicateForString:(NSString *)searchString withProperty:(NSString *)property
{

   // searchString = [searchString stringForSearch];
    NSArray *searchStrings = [searchString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

    NSMutableArray<NSPredicate *> *subPredicates = [NSMutableArray array];

    for (NSString *string in searchStrings)
        if (![string isEqualToString:@""]) {
            NSString *mainString = [property stringByAppendingString:@" CONTAINS[cd] "];        
            mainString = [NSString stringWithFormat:@"%@ CONTAINS[cd] %%@",property];
            NSPredicate *predicate = [NSPredicate predicateWithFormat:mainString, string];
            [subPredicates addObject:predicate];
        }


    if ([searchString containsString:@" "] && subPredicates.count > 0) {
        NSString *mainString = [property stringByAppendingString:@" CONTAINS[cd] "];
        mainString = [mainString stringByAppendingString:@"' '"];

        NSPredicate *emptySpacePredicate = [NSPredicate predicateWithFormat:mainString, nil];

        [subPredicates addObject:emptySpacePredicate];
    }


    NSCompoundPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:subPredicates];

    return predicate;
}

      

suppose we have an object Contact

with the propertyname

NSPredicate *namePredicate = [self wordBasedPredicateForString:searchString withProperty: @"name"];

      

then filter the array:



NSArray *results = [contacts filteredArrayUsingPredicate:namePredicate];

      

and of course you can do multiple word base predicates for name, company, address, etc. and create one compound file like this:

orPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[namePredicate, addressPredicate, phonePredicate]];

      

Hope this helps;)

+3


source


You can also try this solution

Let's take the MyContact

class

class MyContact: NSManagedObject {

    @NSManaged var contact_id: String // Primary key
    @NSManaged var firstname: String
    @NSManaged var lastname: String

    var fullName: String {
        return firstname + " " + lastname
    }

}

      

You now have a string fullName

in your object. so you can easily run a predicate on it. it doesn't matter if yours searchString

matches your first or last name.

Now add your search logic: -



var currentContacts : [MyContact] = []
var contacts : [MyContact] = []

      

Your tableView delegate method, array currentContacts

and array used contacts

just hold all pins.

You can filter the array contacts

according to your search string.

currentContacts = contacts.filter { (element: MyContact) -> Bool in
    return element.fullName.localizedCaseInsensitiveContainsString(searchString)
}
tableView.reloadData()

      

Hope this helps;)

+1


source







All Articles