Multi Hits
MultiIndexHitsConnector( appID: ApplicationID, apiKey: APIKey, indexModules: [IndexModule], controller: MultiIndexHitsController )
About this widget
MultiHits
manages and displays a paginated list of search results from multiple indices. It performs multiple search requests simultaneously and enables some features of a good search experience like Query Suggestions.
This is useful if you want to show all the search results from different indices in one view.
Otherwise, you can keep references to HitsInteractors
tied to individual indices and create a separate HitsController
for each of them.
Examples
Instantiate a HitsInteractor
for each index parametrized with a Codable
type representing the hit in the index.
1
2
3
4
5
6
7
8
9
10
struct Actor: Codable {
...
}
struct Movie: Codable {
...
}
let actorHitsInteractor: HitsInteractor<Actor> = .init(infiniteScrolling: .off)
let movieHitsInteractor: HitsInteractor<Movie> = .init(infiniteScrolling: .off)
Then, you can initialize a MultiIndexHitsConnector
, providing your application ID and search API key and instantiating an IndexModule
for each index.
You can also provide an optional FilterState
while instantiating an IndexModule
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let actorHitsInteractor: HitsInteractor<Actor> = .init(infiniteScrolling: .off)
let movieHitsInteractor: HitsInteractor<Movie> = .init(infiniteScrolling: .off)
let movieFilterState: FilterState = .init()
let hitsTableViewController = MultiIndexHitsTableController(tableView: .init())
let multiIndexHitsConnector = MultiIndexHitsConnector(appID: "YourApplicationID",
apiKey: "YourSearchOnlyAPIKey",
indexModules: [
.init(indexName: "actors",
hitsInteractor: actorHitsInteractor),
.init(indexName: "movies",
hitsInteractor: movieHitsInteractor,
filterState: movieFilterState)
],
controller: hitsTableViewController)
Parameters
appID
|
type: ApplicationID
Required
The ID of your application. |
apiKey
|
type: APIKey
Required
Your application API Key. Be sure to use your Search-only API key. |
indexModules
|
type: [IndexModule]
Required
The list of components representing the single index, containing its name, hits interactor and an optional filter state. |
searcher
|
type: MultiIndexSearcher
Required
The |
interactor
|
type: MultIndexHitsInteractor
Required
The logic applied to the hits. |
filterStates
|
type: [FilterState?]
Optional
The list of FilterStates that will hold your filters separately for each index. |
controller
|
type: MultiIndexHitsController
default: nil
Optional
The Controller interfacing with a concrete multi-index hits view. |
Low-level API
If you want to fully control the MultiHits
components and connect them manually, you can use the following components:
MultiIndexSearcher
: TheSearcher
that handles your searches.MultiIndexHitsInteractor
: The logic applied to the multi-index search results.MultiIndexHitsController
: The controller that interfaces with a concrete multi-index hits view.
Example
Instantiate MultiIndexSearcher
with your application ID, search API key, and list of index names.
1
2
3
let searcher: MultiIndexSearcher = .init(appID: "YourApplicationID",
apiKey: "YourSearchOnlyAPIKey",
indexNames: ["actors", "movies"])
Instantiate a HitsInteractor
for each index.
1
2
let actorHitsInteractor: HitsInteractor<Actor> = .init(infiniteScrolling: .off)
let movieHitsInteractor: HitsInteractor<Movie> = .init(infiniteScrolling: .off)
Instantiate the MultiIndexHitsInteractor
providing a list of the previously instantiated HitsInteractors as a parameter.
When instantiating a MultiIndexSearcher
, the position of an index in the list of indices must match the position of the corresponding HitsInteractor
in the list used when instantiating the MultiIndexInteractor
parameter.
1
let hitsInteractor: MultiIndexHitsInteractor = .init(hitsInteractors: [actorHitsInteractor, movieHitsInteractor])
Connect the MultiIndexHitsInteractor
with the MultiIndexSearcher
using the connectSearcher
method.
1
hitsInteractor.connectSearcher(searcher)
Instantiate the MultiIndexHitsController
implementation and connect it with the MultiIndexHitsInteractor
using the connectController
method.
1
2
let hitsTableViewController = MultiIndexHitsTableController(tableView: .init())
hitsInteractor.connectController(hitsTableViewController)
If you need a FilterState
for an index, instantiate and connect it with a concrete HitsInteractor
and MultiIndexSearcher
using the position of the index in list of indices you used when instantiating the MultiIndexSearcher
1
2
3
let movieFilterState: FilterState = .init()
movieHitsInteractor.connectFilterState(movieFilterState)
searcher.connectFilterState(movieFilterState, withQueryAtIndex: 1)
Now, each time you launch a new search:
- The
Searcher
receives new results and transmit them toHitsInteractor
- The
HitsInteractor
parses search results and notifiesHitsController
- The
HitsController
refreshes the view presenting the hits
## Connecting separate Controllers
To display each index’s hits in a different Controller
, you can use theHitsTableViewController
or the HitsCollectionViewController
described in the Hits guide. Using these Controllers
, you can connect each index’s hits to its own HitsInteractors
.
1
2
3
4
5
6
7
8
9
let actorHitsInteractor: HitsInteractor<Actor> = .init(infiniteScrolling: .off)
let actorsTableViewController = HitsTableViewController<ActorCellConfigurator>()
actorHitsInteractor.connectController(actorsTableViewController)
let movieHitsInteractor: HitsInteractor<Movie> = .init(infiniteScrolling: .off)
let moviesTableViewController = HitsTableViewController<MovieCellConfigurator>()
movieHitsInteractor.connectController(moviesTableViewController)
let hitsInteractor: MultiIndexHitsInteractor = .init(hitsInteractors: [actorHitsInteractor, movieHitsInteractor])
You can connect your own implementation of the HitsController
protocol for Hits
.
## Customizing your view
The default controllers provided, e.g. HitsTableViewController
and HitsCollectionViewController
, work well when you want to use native UIKit components with their default behavior.
They are not suitable if you want to present the hits from the different indices in the same view, for example in different sections of one UITableView
.
For this use case, you must create your own controller conforming to the MultiIndexHitsController
protocol.
### Protocol
var hitsSource: MultiIndexHitsSource?
:
Reference to an entity providing a list of hits per section.
func reload()
:
Function called when we require a reload of the hits view.
func scrollToTop()
:
Function called when we have to scroll to the top of the hits view.
### Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MultiIndexHitsTableController: NSObject, MultiIndexHitsController {
public let tableView: UITableView
public weak var hitsSource: MultiIndexHitsSource?
public init(tableView: UITableView) {
self.tableView = tableView
}
public func reload() {
tableView.reloadData()
}
public func scrollToTop() {
guard tableView.numberOfRows(inSection: 0) != 0 else { return }
let indexPath = IndexPath(row: 0, section: 0)
self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
}
}