With iOS 9, Apple bring many new things for iOS developer. Let’s talk about spotlight search. In iOS 9 new frame work added called “Core Spotlight” which is used to add our app information searchable in spotlight search.
There are 2 way to indexes:
- A private on-device index
Each device contains a private index whose information is never shared with Apple or synced between devices. When you make an item available in a user’s on-device index, only that user can view the item in search results. - Apple’s server-side index
The server-side index stores only publicly available data that you’ve marked appropriately on your website.
Now, we are going to see the first way of index by example.
Let’s create new project which display list of restaurants in tableview.
First we create plist file to store information of restaurant [name, description & image].
After that we will fetch restaurant list from plist file & store in array of restaurant model class.
func loadRestaurants() { // we have created Restaurants.plist file in our main bundle if let path = Bundle.main.url(forResource: "Restaurants", withExtension:"plist") { if let arrObj = NSArray(contentsOf: path) as? [[String:String]] { for (_,value) in arrObj.enumerated() { self.restaurantsArr.append(Restaurant(dict: value)) } } } tblView.reloadData() //reload tableview } //Model class Restaurant: NSObject { var name : String var desc : String var imgName : String init(dict: Dictionary<String,String>) { self.name = dict["Title"]! self.desc = dict["Description"]! self.imgName = dict["Image"]! } }
Now as iOS developer we know tableview control, so we will display list of restaurants in table
Using below code we are able to display restaurant’s list in tableview.
//MARK:- UITableViewDelegate,UITableViewDataSource extension RestaurantListVC:UITableViewDelegate,UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return restaurantsArr.count } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 140 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! RestaurantCell cell.lblTitle.text = restaurantsArr[indexPath.row].name cell.lblDescription.text = restaurantsArr[indexPath.row].desc cell.imgV.image = UIImage(named: restaurantsArr[indexPath.row].imgName) return cell } } //Cell class class RestaurantCell: UITableViewCell { @IBOutlet var lblTitle:UILabel! @IBOutlet var lblDescription:UILabel! @IBOutlet var imgV:UIImageView! }
Before we start integration of spotlight search, we must import two frameworks first:
import CoreSpotlight import MobileCoreServices
Here we have to understand 3 class & use of it:
- CSSearchableItem
First we will create searchable item object & configure with attribute set & domainIdentifier.
DomainIdentifier is used to identify the items group. It’s option argument. We can delete all items of that identifier. - CSSearchableItemAttributeSet
Using attributes we set basic properly like title, description, thumbnailURL & keywords.
title: Heading title of our item in search result.
contentDescription: 2 lines of description in search result below the title.
thumbnailURL: file url which is stored in app
thumbnailData: you can store server image. First download from url set as Data.
keywords: Indicate that user searches by keyword. If items match, it will list in spotlight. - CSSearchableIndex
Finally we add our items in array object using indexSearchableItems method of CSSearchableIndex class.
See the code snippet.
func addToSpotlight() { var searchableItems = [CSSearchableItem]() for(index,objRes) in restaurantsArr.enumerated() { let searchableItemAttributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeText as String) searchableItemAttributeSet.title = objRes.name searchableItemAttributeSet.thumbnailURL = Bundle.main.url(forResource: objRes.imgName, withExtension: ".jpeg") searchableItemAttributeSet.contentDescription = objRes.desc searchableItemAttributeSet.keywords = [objRes.name,"Restaurant"] let searchableItem = CSSearchableItem(uniqueIdentifier: "com.test.spotlight.\(index)", domainIdentifier: "Restaurant", attributeSet: searchableItemAttributeSet) searchableItems.append(searchableItem) } CSSearchableIndex.default().indexSearchableItems(searchableItems) { (error) -> Void in if error != nil { print(error?.localizedDescription ?? "failed") } } }
let go line by line to make clear.
- First, Create searchableItem array Object which hold all items to indexed in spotlight search.
- second, Create searchableItemAttributeSet object & set all basic property.
- Without keyword there is no result in spotlight. We must set related keyword to item.
- Then configure the item with identifier & attributeSet append to searchableItems array object.
At last by calling indexSearchableItems it’s indexed to spotlight search. Here we have to pass items array.
It’s not finished yet buddy, Still we have one more interesting thing to learn.
How to handle item tap event in spotlight & navigate to specific screen in our app.
In our appDelegate file we have delegate method which received event when user tap on item.
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool
We have implemented this method & handle ahead using NSNotificationCenter and post a custom notification, which handle in the ViewController class.
userActivity object contain userInfo dictionary has identifier value which we set during created CSSearchableItem object in addToSpotlight method.
For more handling code download our project & run it.
We missed one more thing, after adding at spotlight if we need to update or delete item, How we can do that?
We have to look in CSSearchableIndex class have method for update & delete items. We will look only delete here.
see the below code snippet for delete.
func deleteSearchIndex() { CSSearchableIndex.default().deleteAllSearchableItems { (error) in if let error = error { print("error: \(error.localizedDescription)") } else { print("Search item successfully removed!") } } }
It will remove all the items from the spotlight index.