TestsTested | ✗ |
LangLanguage | Obj-CObjective C |
License | MIT |
ReleasedLast Release | Apr 2016 |
Maintained by Marian Paul.
Developed and Maintained by Ipodishima Founder & CTO at Wasappli Inc. (If you need to develop an app, get in touch with our team!)
With iOS 9 comes great new features. One of them is CoreSpotlight which purpose is to give you access to the app search on iOS itself. A user can now search for it's hotel booking straight from the search on iOS and get back to the app.
Because several developpers are using CoreData, I thought it would have been a great idea to help indexing using both CoreSpotlight and CoreData apis.
WACoreDataSpotlight, after a quick configuration, automatically index you core data database. Yeah, you heard it. Automatically.
It will:
Automatically (after a save)
You can use
pod try WACoreDataSpotlight
Then, when the app is launched, go back to the springboard, search for Marian Paul
for exemple, of for employee
#import <WACoreDataSpotlight/WACoreDataSpotlight.h>
For allocating the indexer, you need a valid NSManagedObjectContext
you are using to create / fetch / etc you core data objects.
self.mainIndexer = [[WACDSIndexer alloc] initWithManagedObjectContext:mainContext];
Then, you need to create some mappings. You can use WACDSSimpleMapping
if it remains simple, or WACDSCustomMapping
if you need more access on CSSearchableItemAttributeSet
.
Let's start with an easy one
WACDSSimpleMapping *employeeSearchMapping =
[[WACDSSimpleMapping alloc] initWithManagedObjectEntityName:@"Employee"
uniqueIdentifierPattern:@"employee_{#firstName#}_{#lastName#}"
titlePattern:@"{#firstName#} {#lastName#}"
contentDescriptionPattern:@"{#firstName#} {#lastName#} is working as {#jobTitle#} on {#company.name#}"
keywordsPatterns:@[@"employee", @"{#firstName#}", @"{#lastName#}"]
thumbnailDataBuilder:^NSData *(Employee *employee) {
return UIImagePNGRepresentation([UIImage imageNamed:employee.avatarImageName]);
}];
First, you pass Employee
class which is a subclass of NSManagedObject
.
Then you need to pass a unique identifier pattern. It is used to id your object in an unique way in the index. Best idea is to use an itemID
property.
Let's stop with the syntax. Assuming Employee
has a property firstName
and lastName
which values are Marian
and Paul
, using an identifier as employee_{#firstName#}_{#lastName#}
will be mapped to employee_Marian_Paul
.
{#object property name#}
is THE syntax you need to use for this to work correctly.
The titlePattern
is mandatory.
Keywords can be hard values (employee
) or dynamic ({#firstName#}
).
[self.mainIndexer registerMapping:employeeSearchMapping];
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler {
NSManagedObject *object = [self.mainIndexer objectFromUserActivity:userActivity];
// Do something with the object
return YES;
}
Build and run the app. Every objects for which you added a mapping on their classe are now automatically added / updated / deleted from the index... !
You can use custom mapping to create your own attribute set. For example:
WACDSCustomMapping *companyMapping =
[[WACDSCustomMapping alloc] initWithManagedObjectEntityName:@"Company"
uniqueIdentifierPattern:@"company_{#name#}"
searchableItemAttributeSetBuilder:^CSSearchableItemAttributeSet *(Company *company) {
CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString *)kUTTypeText];
attributeSet.title = company.name;
attributeSet.contentDescription = [NSString stringWithFormat:@"The company has its offices in %@ and its primary activity is %@.\n%ld employees", company.address, company.activity, [company.employees count]];
attributeSet.keywords = @[@"company", company.name, company.activity];
return attributeSet;
}];
[self.mainIndexer registerMapping:companyMapping];
You can index existing objects using [self.indexer indexExistingObjects:existingObjects];
Please not that this is up to you to call this only one time in the app's life.
Assuming you have an object to index which requires an image download from the URL. Indexing would give the order to download the image, but at the end you need to refresh the index to pass the image.
[self.mainIndexer updateIndexingForObject:company];
When the user hits the search result, you grab the object using [self.mainIndexer objectFromUserActivity:userActivity]
.
But then what?
Well, you could use for example (WAAppRouting)[https://github.com/Wasappli/WAAppRouting] to add some url behavior in your app. It would be as easy as doing:
self.router = [WAAppRouter defaultRouter];
[self.router.registrar
registerAppRoutePath:@"companies{CompaniesTableViewController}/:companyName{EmployeesTableViewController}/:employeeID{EmployeeFormViewController}!"
presentingController:nav];
And then on application: continueUserActivity: restorationHandler:
NSManagedObject *object = [self.mainIndexer objectFromUserActivity:userActivity];
if ([object isKindOfClass:[Company class]]) {
[AppLink goTo:@"companies/%@", ((Company *)object).name];
}
if ([object isKindOfClass:[Employee class]]) {
[AppLink goTo:@"companies/%@/%@", ((Employee *)object).company.name, ((Employee *)object).employeeID];
}
Please open a new Issue here if you run into a problem specific to WACoreDataSpotlight.
For new features pull requests are encouraged and greatly appreciated! Please try to maintain consistency with the existing code style. If you're considering taking on significant changes or additions to the project, please ask me before by opening a new issue to have a chance for a merge.