Created an separate sample app, pretty sure this feature is not working as per video.
import SwiftUI
import CoreSpotlight
import UniformTypeIdentifiers
@main
struct SemanticSearchApp: App {
init() {
// Prepare Core Spotlight for searching
CSUserQuery.prepare()
// Index sample items when app launches
indexSampleItems()
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
private func indexSampleItems() {
let items = [
("windsurfing-1", "The Best Windsurfing Carmel County", "Learn about the best windsurfing spots in Carmel County"),
("windsurfing-2", "Windsurfing Lessons", "Professional windsurfing lessons for beginners"),
("windsurfing-3", "Sailboarding Lessons", "Expert sailboarding instruction in Carmel")
].map { (id, title, description) -> CSSearchableItem in
let attributeSet = CSSearchableItemAttributeSet(contentType: .text)
attributeSet.title = title
attributeSet.contentDescription = description
return CSSearchableItem(
uniqueIdentifier: id,
domainIdentifier: "com.example.windsurfing",
attributeSet: attributeSet
)
}
// Use batch indexing for better performance
let index = CSSearchableIndex(name: "SpotlightSearchSample")
index.fetchLastClientState { state, error in
if error == nil {
index.beginBatch()
index.indexSearchableItems(items) { error in
if let error = error {
print("Indexing error: \(error.localizedDescription)")
}
}
// Create new state data (could be a timestamp or counter)
let newState = "batch1".data(using: .utf8) ?? Data()
index.endBatch(withClientState: newState) { error in
if let error = error {
print("Batch error: \(error.localizedDescription)")
}
}
}
}
}
}
struct ContentView: View {
@State private var query: String = ""
@State private var searchResults: [SearchResult] = []
@State private var suggestions: [String] = []
@State private var allItems: [SearchResult] = [
SearchResult(
id: "windsurfing-1",
title: "The Best Windsurfing Carmel County",
description: "Learn about the best windsurfing spots in Carmel County"
),
SearchResult(
id: "windsurfing-2",
title: "Windsurfing Lessons",
description: "Professional windsurfing lessons for beginners"
),
SearchResult(
id: "windsurfing-3",
title: "Sailboarding Lessons",
description: "Expert sailboarding instruction in Carmel"
)
]
var body: some View {
NavigationStack {
List(query.isEmpty ? allItems : searchResults) { result in
VStack(alignment: .leading) {
Text(result.title)
.font(.headline)
Text(result.description)
.font(.subheadline)
.foregroundColor(.gray)
}
}
.navigationTitle("Search Playground")
.searchable(
text: $query,
prompt: "Search items",
suggestions: {
ForEach(suggestions, id: \.self) { suggestion in
Text(suggestion)
.searchCompletion(suggestion)
}
}
)
.onChange(of: query) { newValue in
performSearch(newValue)
}
}
.padding()
.frame(minWidth: 400, minHeight: 500)
}
private func performSearch(_ searchText: String) {
guard !searchText.isEmpty else {
searchResults = []
suggestions = []
return
}
let queryContext = CSUserQueryContext()
queryContext.fetchAttributes = ["title", "contentDescription"]
queryContext.maxSuggestionCount = 5
queryContext.enableRankedResults = true
let searchQuery = CSUserQuery(userQueryString: searchText, userQueryContext: queryContext)
Task {
do {
var newResults: [SearchResult] = []
var newSuggestions: [String] = []
for try await element in searchQuery.responses {
switch element {
case .item(let queryItem):
if let title = queryItem.item.attributeSet.title,
let description = queryItem.item.attributeSet.contentDescription {
let result = SearchResult(
id: queryItem.item.uniqueIdentifier,
title: title,
description: description
)
newResults.append(result)
}
case .suggestion(let suggestion):
newSuggestions.append(String(suggestion.suggestion.localizedAttributedSuggestion.characters))
@unknown default:
break
}
}
await MainActor.run {
self.searchResults = newResults
self.suggestions = newSuggestions
}
} catch {
print("Search error: \(error.localizedDescription)")
}
}
}
}
struct SearchResult: Identifiable {
let id: String
let title: String
let description: String
}