When you create an attributes set, it's important that you populate it correctly since it describes almost all of the important information about your item for Spotlight. You can set a title, content description, a thumbnail image, keywords, even ratings or phone numbers, GPS information, and much, much more. For a full overview of what's possible, refer to the CSSearchableItemAttributeSet documentation. Every time you are about to create a new item that can be indexed, you should take a look at the documentation to make sure you don't miss any attributes.
The better use you make of the available attributes, the more effectively your content can be indexed and the higher your app will rank. Therefore, it's worth putting slightly more time and effort into your search attributes because getting it wrong can be a costly mistake, especially considering the available documentation. At a minimum, you should always try to set title, contentDescription, thumbnailData, rating, and keywords. This isn't always relevant or even possible for the items you're indexing, but whenever possible make sure that you set these attributes.
You may have noticed that the NSUserActivity instances you indexed in the app didn't receive any special attributes. You just set a name and some other basic information, but you didn't have to add a description or a rating to any of the indexed objects. If you index user activities in your applications, it's worth noting that user activities can and should have attributes associated with them. All you need to do is set the contentAttributeSet property on the user activity. After you implement indexing through CSSearchableItem, you should shortly revisit user-activity indexing to make the indexed item richer and also to make sure that CoreSpotlight understands that the user activities and searchable items point to the same underlying index in Spotlight.
When you index items through multiple methods, it's inevitable that you run into data duplication. The MustC app indexes every visited screen. So, if a user visits the details page of a movie, a user activity for that movie should be created. However, you also want to index movies as they are created by the user. To avoid duplicate results in Spotlight search, relatedUniqueIdentifier should be added to the attributes set. Setting this attribute on a user activity makes sure that Spotlight doesn't add duplicate entries for items with the same identifier.
Let's expand IndexingFactory with two methods that can generate attribute sets for searchable items. Putting this functionality in IndexingFactory as a separate method is a good idea because, if it is set up correctly, these methods can be used to generate attributes for both user activities and searchable items. This avoids code duplication and makes it a lot easier to add or remove properties in the future. Add the following methods to the IndexingFactory struct. Don't forget to import CoreSpotlight at the top of the file:
static func searchableAttributes(forMovie movie: Movie) -> CSSearchableItemAttributeSet { do { try movie.managedObjectContext?.obtainPermanentIDs(for: [movie]) } catch { print("could not obtain permanent movie id") } let attributes = CSSearchableItemAttributeSet(itemContentType: ActivityType.movieDetailView.rawValue) attributes.title = movie.title attributes.contentDescription = "A movie that is favorited by (movie.familyMembers?.count ?? 0) family members" attributes.rating = NSNumber(value: movie.popularity) attributes.identifier = "(movie.objectID.uriRepresentation().absoluteString)" attributes.relatedUniqueIdentifier = "(movie.objectID.uriRepresentation().absoluteString)" return attributes } static func searchableAttributes(forFamilyMember familyMember: FamilyMember) -> CSSearchableItemAttributeSet { do { try familyMember.managedObjectContext?.obtainPermanentIDs(for: [familyMember]) } catch { print("could not obtain permanent family member id") } let attributes = CSSearchableItemAttributeSet(itemContentType: ActivityType.familyMemberDetailView.rawValue) attributes.title = familyMember.name attributes.identifier = "(familyMember.objectID.uriRepresentation().absoluteString)" attributes.contentDescription = "Family Member with (familyMember.favoriteMovies?.count ?? 0) listed movies" attributes.relatedUniqueIdentifier = "(familyMember.objectID.uriRepresentation().absoluteString)" return attributes }
For both the Movie and FamilyMember objects, a set of attributes is created. This set meets Apple's recommendations as closely as possible. The objects don't have any thumbnail images or keywords that can be added to the attributes set other than the movie title or the name of a family member. Adding these to the keywords is kind of pointless because the title in itself is essentially a keyword that the item will match on.
To create an attribute set for a movie or family member, you only have to call the method that matches the object you want to index and you're good to go. Beautiful, convenient, and simple.