Objective-C中的Core Spotlight内容搜索集成
Core Spotlight简介
Core Spotlight是iOS 9引入的一项强大功能,它允许应用程序将其内容索引到系统搜索中。这意味着用户在使用设备的全局搜索功能(如在主屏幕上向下滑动)时,不仅可以搜索到系统自带应用的数据,还能搜索到集成了Core Spotlight的第三方应用的内容。这种无缝集成提升了用户体验,因为他们无需打开特定应用就能快速找到所需信息。
Core Spotlight的工作原理
Core Spotlight依赖于一个称为CSSearchableIndex
的类来管理应用程序的搜索索引。当应用程序创建或更新内容时,它会向CSSearchableIndex
添加或更新相应的搜索记录。这些记录包含了要被搜索的内容的元数据,如标题、描述、唯一标识符等。系统在后台会对这些索引进行优化,以便快速响应搜索请求。
当用户发起搜索时,系统会查询所有已注册的CSSearchableIndex
,包括来自第三方应用的索引。如果搜索词匹配任何索引中的记录,相关结果就会显示在搜索结果列表中。用户点击结果后,系统会启动相应的应用,并将用户导航到与该搜索结果相关的内容页面。
在Objective - C中集成Core Spotlight
配置项目
首先,在Xcode项目中,需要确保应用支持Core Spotlight。这通常涉及在Info.plist
文件中进行一些配置。打开项目的Info.plist
文件,添加以下键值对:
<key>NSUserActivityTypes</key>
<array>
<string>your.activity.type</string>
</array>
这里的your.activity.type
是自定义的活动类型,用于标识应用内特定的活动。它应该遵循反向域名命名规则,例如com.example.app.activityType
。这个活动类型将在后续配置搜索结果的深层链接时用到。
创建搜索记录
在Objective - C中,创建搜索记录涉及到CSSearchableItemAttributeSet
和CSSearchableItem
这两个类。CSSearchableItemAttributeSet
用于定义搜索记录的属性,如标题、描述、关键字等。而CSSearchableItem
则将这些属性集与一个唯一标识符关联起来,形成一个完整的搜索记录。
以下是创建一个简单搜索记录的代码示例:
#import <CoreSpotlight/CoreSpotlight.h>
#import <MobileCoreServices/MobileCoreServices.h>
// 创建一个CSSearchableItemAttributeSet对象
CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString *)kUTTypeText];
attributeSet.title = @"示例文章";
attributeSet.contentDescription = @"这是一篇关于Core Spotlight集成的示例文章";
attributeSet.keywords = @[@"Core Spotlight", @"iOS开发", @"Objective - C"];
// 创建一个CSSearchableItem对象
CSSearchableItem *searchableItem = [[CSSearchableItem alloc] initWithUniqueIdentifier:@"article1" domainIdentifier:@"com.example.app" attributeSet:attributeSet];
在上述代码中,首先创建了一个CSSearchableItemAttributeSet
对象,并设置了标题、描述和关键字。itemContentType
指定了内容的类型,这里使用kUTTypeText
表示文本类型。然后,通过CSSearchableItem
的初始化方法,将唯一标识符article1
、域名标识符com.example.app
与属性集关联起来,创建了一个完整的搜索记录。
添加搜索记录到索引
创建好搜索记录后,需要将其添加到CSSearchableIndex
中。CSSearchableIndex
类提供了一个共享实例,可以通过defaultSearchableIndex
方法获取。
CSSearchableIndex *searchableIndex = [CSSearchableIndex defaultSearchableIndex];
[searchableIndex indexSearchableItems:@[searchableItem] completionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(@"添加搜索记录失败: %@", error);
} else {
NSLog(@"搜索记录添加成功");
}
}];
在这段代码中,获取了CSSearchableIndex
的共享实例,并调用indexSearchableItems:completionHandler:
方法将之前创建的搜索记录添加到索引中。完成处理程序会在操作完成后被调用,通过检查error
参数可以判断操作是否成功。
更新和删除搜索记录
如果应用中的内容发生了变化,可能需要更新或删除相应的搜索记录。
更新搜索记录
更新搜索记录的过程与添加类似,只需要创建一个具有相同唯一标识符但属性已更新的新CSSearchableItem
,然后调用indexSearchableItems:
方法。例如,如果要更新之前创建的文章的标题:
// 更新CSSearchableItemAttributeSet的标题
attributeSet.title = @"更新后的示例文章";
// 创建一个新的CSSearchableItem,使用相同的唯一标识符
CSSearchableItem *updatedSearchableItem = [[CSSearchableItem alloc] initWithUniqueIdentifier:@"article1" domainIdentifier:@"com.example.app" attributeSet:attributeSet];
// 更新索引
[searchableIndex indexSearchableItems:@[updatedSearchableItem] completionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(@"更新搜索记录失败: %@", error);
} else {
NSLog(@"搜索记录更新成功");
}
}];
删除搜索记录
删除搜索记录可以通过调用CSSearchableIndex
的deleteSearchableItemsWithIdentifiers:completionHandler:
方法实现。例如,要删除之前创建的文章的搜索记录:
[searchableIndex deleteSearchableItemsWithIdentifiers:@[@"article1"] completionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(@"删除搜索记录失败: %@", error);
} else {
NSLog(@"搜索记录删除成功");
}
}];
处理搜索结果
当用户点击搜索结果时,应用需要处理该点击事件,并将用户导航到相应的内容页面。这涉及到在应用的AppDelegate
中实现application:continueUserActivity:restorationHandler:
方法。
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
if ([userActivity.activityType isEqualToString:@"your.activity.type"]) {
NSString *uniqueIdentifier = userActivity.userInfo[CSSearchableItemActivityIdentifier];
// 根据唯一标识符导航到相应的内容页面
// 这里假设存在一个ArticleViewController用于显示文章内容
ArticleViewController *articleVC = [[ArticleViewController alloc] initWithArticleID:uniqueIdentifier];
UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
[navController pushViewController:articleVC animated:YES];
return YES;
}
return NO;
}
在上述代码中,首先检查userActivity
的activityType
是否与在Info.plist
中定义的活动类型一致。如果一致,从userActivity
的userInfo
字典中获取搜索记录的唯一标识符。然后,根据这个唯一标识符创建相应的视图控制器,并将其推送到导航堆栈中,实现用户到具体内容页面的导航。
Core Spotlight的高级应用
搜索记录的权重设置
Core Spotlight允许为搜索记录设置权重,以影响它们在搜索结果中的排名。可以通过CSSearchableItemAttributeSet
的weight
属性来设置权重。权重值的范围是从0.0(最低权重)到1.0(最高权重)。例如,对于更重要的文章,可以设置较高的权重:
// 设置较高的权重
attributeSet.weight = 0.8;
这样,在搜索结果中,权重较高的记录更有可能出现在靠前的位置。
搜索记录的分组
有时候,可能希望将搜索记录进行分组展示,以便用户更清晰地浏览搜索结果。Core Spotlight支持通过domainIdentifier
来实现分组。如果多个搜索记录具有相同的domainIdentifier
,它们将在搜索结果中被分组显示。例如,可以根据文章的类别来设置domainIdentifier
:
// 假设文章属于“技术”类别
CSSearchableItem *techArticle = [[CSSearchableItem alloc] initWithUniqueIdentifier:@"techArticle1" domainIdentifier:@"com.example.app.tech" attributeSet:techAttributeSet];
// 假设文章属于“生活”类别
CSSearchableItem *lifeArticle = [[CSSearchableItem alloc] initWithUniqueIdentifier:@"lifeArticle1" domainIdentifier:@"com.example.app.life" attributeSet:lifeAttributeSet];
在搜索结果中,属于“技术”类别的文章会被归为一组,属于“生活”类别的文章会被归为另一组。
搜索记录的过滤
在某些情况下,可能只希望特定类型的搜索记录出现在搜索结果中。可以通过设置CSSearchableIndex
的filter
属性来实现过滤。例如,如果只想显示文本类型的搜索记录,可以这样设置:
CSSearchableIndex *searchableIndex = [CSSearchableIndex defaultSearchableIndex];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"contentType == %@", (NSString *)kUTTypeText];
searchableIndex.filter = predicate;
上述代码创建了一个谓词,用于筛选出内容类型为文本的搜索记录,并将其设置为CSSearchableIndex
的过滤条件。这样,在搜索时,只有符合过滤条件的记录才会出现在搜索结果中。
Core Spotlight的性能优化
批量操作
为了提高性能,尽量使用批量操作来添加、更新或删除搜索记录。例如,一次添加多个搜索记录:
// 创建多个搜索记录
CSSearchableItem *item1 = [[CSSearchableItem alloc] initWithUniqueIdentifier:@"item1" domainIdentifier:@"com.example.app" attributeSet:attributeSet1];
CSSearchableItem *item2 = [[CSSearchableItem alloc] initWithUniqueIdentifier:@"item2" domainIdentifier:@"com.example.app" attributeSet:attributeSet2];
// 批量添加
[searchableIndex indexSearchableItems:@[item1, item2] completionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(@"批量添加搜索记录失败: %@", error);
} else {
NSLog(@"批量搜索记录添加成功");
}
}];
通过批量操作,可以减少与系统索引交互的次数,从而提高效率。
异步操作
所有与CSSearchableIndex
的交互操作,如添加、更新和删除,都应该在后台线程中进行,以避免阻塞主线程,影响应用的响应性。可以使用dispatch_async
来实现异步操作:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[searchableIndex indexSearchableItems:@[searchableItem] completionHandler:^(NSError * _Nullable error) {
if (error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"添加搜索记录失败: %@", error);
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"搜索记录添加成功");
});
}
}];
});
在上述代码中,首先在后台队列中执行添加搜索记录的操作。如果操作完成后有错误或成功的消息需要处理,再将相应的日志打印操作切换到主线程执行,以确保UI相关的操作在主线程进行。
索引维护
定期清理不再需要的搜索记录,以保持索引的整洁和高效。例如,当应用中的某些内容被永久删除时,相应的搜索记录也应该从索引中删除。同时,对于更新频率较高的内容,合理安排更新时间,避免过于频繁地更新索引,从而减少性能开销。
Core Spotlight与其他技术的结合
与Core Data的结合
如果应用使用Core Data来管理数据,可以很方便地将Core Data中的数据与Core Spotlight集成。每当Core Data中的数据发生变化(添加、更新或删除)时,相应地更新Core Spotlight的索引。例如,假设应用有一个Article
实体在Core Data中,并且有一个对应的Article
类:
// 获取Core Data上下文
NSManagedObjectContext *context = [self persistentContainer.viewContext];
// 获取所有文章
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Article"];
NSArray<Article *> *articles = [context executeFetchRequest:fetchRequest error:nil];
// 创建搜索记录数组
NSMutableArray<CSSearchableItem *> *searchableItems = [NSMutableArray array];
for (Article *article in articles) {
CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString *)kUTTypeText];
attributeSet.title = article.title;
attributeSet.contentDescription = article.summary;
attributeSet.keywords = article.keywords;
CSSearchableItem *searchableItem = [[CSSearchableItem alloc] initWithUniqueIdentifier:article.articleID domainIdentifier:@"com.example.app" attributeSet:attributeSet];
[searchableItems addObject:searchableItem];
}
// 批量添加搜索记录
CSSearchableIndex *searchableIndex = [CSSearchableIndex defaultSearchableIndex];
[searchableIndex indexSearchableItems:searchableItems completionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(@"添加搜索记录失败: %@", error);
} else {
NSLog(@"搜索记录添加成功");
}
}];
上述代码从Core Data中获取所有文章,为每篇文章创建一个搜索记录,并批量添加到Core Spotlight索引中。当文章数据在Core Data中更新或删除时,也需要相应地更新或删除Core Spotlight中的搜索记录,以保持数据的一致性。
与CloudKit的结合
对于使用CloudKit进行数据存储和同步的应用,可以将CloudKit中的数据集成到Core Spotlight。CloudKit提供了一种方便的方式来在多个设备之间同步数据,而Core Spotlight则提供了本地搜索功能。例如,当用户在一个设备上创建了一篇新文章并同步到CloudKit后,其他设备可以获取到该文章并将其添加到Core Spotlight索引中。
首先,需要在应用启动时,从CloudKit中获取最新的数据,并更新Core Spotlight索引。假设应用使用CKQuery
来查询CloudKit中的文章数据:
// 创建一个查询,获取所有文章
CKQuery *query = [[CKQuery alloc] initWithRecordType:@"Article" predicate:[NSPredicate predicateWithValue:YES]];
CKQueryOperation *queryOperation = [[CKQueryOperation alloc] initWithQuery:query];
queryOperation.recordFetchedBlock = ^(CKRecord * _Nonnull record) {
CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString *)kUTTypeText];
attributeSet.title = record[@"title"];
attributeSet.contentDescription = record[@"summary"];
attributeSet.keywords = record[@"keywords"];
CSSearchableItem *searchableItem = [[CSSearchableItem alloc] initWithUniqueIdentifier:record.recordID.recordName domainIdentifier:@"com.example.app" attributeSet:attributeSet];
CSSearchableIndex *searchableIndex = [CSSearchableIndex defaultSearchableIndex];
[searchableIndex indexSearchableItems:@[searchableItem] completionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(@"添加搜索记录失败: %@", error);
} else {
NSLog(@"搜索记录添加成功");
}
}];
};
queryOperation.queryCompletionBlock = ^(CKQueryCursor * _Nullable cursor, NSError * _Nullable error) {
if (error) {
NSLog(@"查询CloudKit数据失败: %@", error);
}
};
[[CKContainer defaultContainer].publicCloudDatabase addOperation:queryOperation];
上述代码创建了一个CKQuery
来获取所有Article
类型的记录。当获取到每条记录时,为其创建一个搜索记录并添加到Core Spotlight索引中。通过这种方式,实现了CloudKit数据与Core Spotlight的集成,使用户可以在本地快速搜索到来自CloudKit的内容。
通过以上详细的介绍和代码示例,相信你对Objective - C中Core Spotlight内容搜索集成有了深入的了解,可以在自己的应用中灵活运用这一强大功能,提升用户体验。无论是简单的内容搜索集成,还是与其他数据管理技术的结合,Core Spotlight都为应用开发带来了更多的可能性。在实际开发过程中,要根据应用的具体需求和特点,合理地进行配置和优化,以达到最佳的搜索效果和性能表现。