Core Spotlight allows iOS apps to index their content and make it searchable within the device. This is particularly useful for apps like a recipe app, where users can quickly find recipes by searching for keywords in Spotlight. In this guide, we will build a simple recipe app that indexes recipes using Core Spotlight.

Prerequisites

  • Basic knowledge of Swift and iOS development
  • Xcode installed

Step 1: Setting Up the Project

  1. Create a New Xcode Project:
    • Open Xcode and create a new project.
    • Choose the “App” template.
    • Name your project (e.g., “RecipeApp”).
    • Select Swift as the language.
  2. Add Core Spotlight Framework:
    • Go to your project settings.
    • Under “General”, find “Frameworks, Libraries, and Embedded Content”.
    • Click the “+” button and add the CoreSpotlight framework.

Step 2: Creating the Recipe Model

Create a model to represent a recipe.

import Foundation

struct Recipe {
    let id: String
    let title: String
    let ingredients: String
    let instructions: String
}

Step 3: Indexing Recipes with Core Spotlight

  1. Import Core Spotlight:
import CoreSpotlight
import MobileCoreServices

Create a Method to Index a Recipe:

func indexRecipe(_ recipe: Recipe) {
    let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeText as String)
    attributeSet.title = recipe.title
    attributeSet.contentDescription = recipe.ingredients
    attributeSet.keywords = recipe.ingredients.components(separatedBy: ", ")
    
    let item = CSSearchableItem(uniqueIdentifier: recipe.id, domainIdentifier: "com.yourdomain.recipeapp", attributeSet: attributeSet)
    
    CSSearchableIndex.default().indexSearchableItems([item]) { error in
        if let error = error {
            print("Indexing error: \(error.localizedDescription)")
        } else {
            print("Recipe successfully indexed!")
        }
    }
}

  1. Call the Indexing Method:

You can call this method when a recipe is added or updated in your app.

let recipe = Recipe(id: "1", title: "Pasta Carbonara", ingredients: "Pasta, Eggs, Cheese, Bacon", instructions: "Cook pasta. Mix eggs and cheese. Add bacon.")
indexRecipe(recipe)

Step 4: Handling Spotlight Searches

To handle Spotlight searches and open the app to the specific recipe, you’ll need to handle the URL scheme or the NSUserActivity.

  1. Update AppDelegate to Handle Searchable Items:

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    if userActivity.activityType == CSSearchableItemActionType {
        if let identifier = userActivity.userInfo?[CSSearchableItemActivityIdentifier] as? String {
            // Handle the identifier and navigate to the specific recipe
            navigateToRecipe(with: identifier)
        }
    }
    return true
}

Implement Navigation Logic:

func navigateToRecipe(with identifier: String) {
    // Logic to navigate to the specific recipe in your app
    print("Navigate to recipe with ID: \(identifier)")
}

Step 5: User Interface

Create a simple UI to display the list of recipes and a detail view for each recipe.

  1. Recipe List View:

import UIKit

class RecipeListViewController: UITableViewController {
    var recipes: [Recipe] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        title = "Recipes"
        
        // Add some sample recipes
        recipes = [
            Recipe(id: "1", title: "Pasta Carbonara", ingredients: "Pasta, Eggs, Cheese, Bacon", instructions: "Cook pasta. Mix eggs and cheese. Add bacon."),
            Recipe(id: "2", title: "Chicken Curry", ingredients: "Chicken, Curry Powder, Coconut Milk", instructions: "Cook chicken. Add curry powder and coconut milk.")
        ]
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return recipes.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "RecipeCell", for: indexPath)
        cell.textLabel?.text = recipes[indexPath.row].title
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let recipe = recipes[indexPath.row]
        let detailVC = RecipeDetailViewController()
        detailVC.recipe = recipe
        navigationController?.pushViewController(detailVC, animated: true)
    }
}

Recipe Detail View:

import UIKit

class RecipeDetailViewController: UIViewController {
    var recipe: Recipe?

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        
        if let recipe = recipe {
            title = recipe.title
            
            let ingredientsLabel = UILabel()
            ingredientsLabel.text = "Ingredients: \(recipe.ingredients)"
            ingredientsLabel.numberOfLines = 0
            ingredientsLabel.frame = CGRect(x: 20, y: 100, width: view.frame.width - 40, height: 100)
            view.addSubview(ingredientsLabel)
            
            let instructionsLabel = UILabel()
            instructionsLabel.text = "Instructions: \(recipe.instructions)"
            instructionsLabel.numberOfLines = 0
            instructionsLabel.frame = CGRect(x: 20, y: 220, width: view.frame.width - 40, height: 200)
            view.addSubview(instructionsLabel)
        }
    }
}

Step 6: Integrating Core Spotlight

Now, index your recipes when you add them to the list.

  1. Index Recipes on Addition:

Update the RecipeListViewController to index recipes when they are added.

override func viewDidLoad() {
    super.viewDidLoad()
    title = "Recipes"
    
    recipes = [
        Recipe(id: "1", title: "Pasta Carbonara", ingredients: "Pasta, Eggs, Cheese, Bacon", instructions: "Cook pasta. Mix eggs and cheese. Add bacon."),
        Recipe(id: "2", title: "Chicken Curry", ingredients: "Chicken, Curry Powder, Coconut Milk", instructions: "Cook chicken. Add curry powder and coconut milk.")
    ]
    
    for recipe in recipes {
        indexRecipe(recipe)
    }
}

You have now built a simple recipe app that uses Core Spotlight to index and search for recipes. This example covers the basic setup, indexing content, handling searches, and creating a simple user interface. You can expand this app with more features, such as adding the ability to edit and delete recipes, adding images, and improving the UI/UX design.