InstantSearch - Issue with HitsTableViewController after updating from v. 5 to v.7

Hello everyone,

I updated my pod file with the entry for the latest version of InstantSearch:

 pod 'InstantSearch', '~> 7.0.0'

After installing, I got couple of compile issues. e. g. I am not able to use HitsTableViewController anymore:

let hitsTableController: HitsTableController<HitsInteractor> = .init(tableView: UITableView())

The line above gives me this error:

‘HitsTableController’ is unavailable: Use your own UITableViewController conforming to HitsController protocol

Also, when I follow the tutorial for InstantSearch, I am not able to use this code:

BestBuyHitsViewController = HitsTableViewController<BestBuyTableViewCellConfigurator>

It says - Use of undeclared type 'HitsTableViewController'

Can anyone please help?

Hello @kaan548,

Thank you for your feedback.
This happens because the pod version in the guide is not up-to-date, it will be fixed.

Setting version 7.1 of the InstantSearch will solve your problem:

pod 'InstantSearch', '~> 7.1'

Thanks @vladislav.fitc :slight_smile:

Hi @vladislav.fitc. Even updating to version 7.1 didn’t solve it. I still get the same exceptions as above!
Screenshot attached

Hi @kaan548,

Yes, HitsTableController is obsoleted, while the HitsTableViewController mentioned in the latest InstantSearch tutorial is available in 7.1.

Hello @vladislav.fitc,

thanks. There is progress on my side. However, what I want to do is still being able to use the delegate of the tableView or collectionView as you can see in the code snippet above.
How do I achieve that? I couldn’t find any documentation regarding that.

I was able to initialize the table view according to my requirements. I want to do exactly the same now also.

In the documentation, there is:

typealias BestBuyHitsViewController = HitsTableViewController <BestBuyTableViewCellConfigurator…>

What would be the most similar approach to this:

let hitsTableController: HitsTableController = .init(tableView: UITableView())

Thanks!

Just need to ask few questions additionally:
Is there no way using following line anymore:

var hitsCollectionViewController: HitsCollectionViewController<HitsInteractor<JSON>> = .init(collectionView: UICollectionView(frame: .zero, collectionViewLayout: .init()))

Instead of HitsInteractor"JSON" (sorry can’t use “<” somehow), I need to provide a collection view cell that is conformed to the CollectionViewCellConfigurable ?

This would mean, I can only display one model for my collection view controller? Because earlier, I could display different entities like this:

if (challengeStateSegmentedControl.selectedSegmentIndex == 0) {
        let challengeObject = Challenge(json: (hitsCollectionViewController.hitsSource?.hit(atIndex: indexPath.row))!)
       ...
    }
    
   else if (challengeStateSegmentedControl.selectedSegmentIndex == 1) {
        let participationObject = Participation(json: (hitsCollectionViewController.hitsSource?.hit(atIndex: indexPath.row))!)
         ...
    } 
  else {
  let ratingObject = Rating(json: (hitsCollectionViewController.hitsSource?.hit(atIndex:   indexPath.row))!)
  ... }

Basically, I triggered a search for different indices and then displayed the objects. Is there a way, I can use the old approach with JSON by keeping the current InstantSearch version?

Even If I try it with the CollectionViewCellConfigurable, somehow I can’t access the number of hits anymore:

return (hitsCollectionViewController.hitsSource!.numberOfHits())

This is the case for the collection view controller. It works fine with the table view controller though.

Hi @vladislav.fitc, @kevin.sullivan could you help me, please?

Thanks!

Hi @kaan548,

The provided HitsTableViewController and HitsCollectionViewController are considered to be used as very basic hits views to quickly get started with Algolia.

If you want do build something more complex don’t be tighten to these basic classes and use your own ViewController conforming to HitsController protocol with UITable(Colllection)ViewDataSource(Delegate) implementations. Don’t use the restricted out-of-box controllers, but create your own. HitsSource provides the necessary methods such as hit(atIndex:) and numberOfHits.

You’ll be able to connect your HitsController implementation to a Connector/Interactor the same way you do with HitsTableViewController.

Hello @vladislav.fitc

OK, I see. So I changed my code:

class SearchChallengeSubView: UIView, HitsController {
    
var queryInputInteractor = QueryInputInteractor()
var singleIndexHitsInteractor: HitsInteractor<JSON> = .init(showItemsOnEmptyQuery: true)
var challengeCollectionView:UICollectionView?
public weak var hitsSource: HitsInteractor<JSON>? 
...
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
   return (hitsSource!.numberOfHits())
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> 
UICollectionViewCell {
 ...
 let challengeObject = Challenge(json: (hitsSource?.hit(atIndex: indexPath.row))!)

This seems to be ok fo far but I don’t know how to connect the searchers…

func setupInstantSearchSettings() {
    queryInputInteractor.connectSearcher(challengeIndexSearcher, searchTriggeringMode: .searchAsYouType) // is ok
    queryInputInteractor.connectController(searchBarController) // is ok
       
    singleIndexHitsInteractor.connectController(self) // What to do here?
    singleIndexHitsInteractor.connectSearcher(challengeIndexSearcher) // is ok
       
    challengeIndexSearcher.search()
}

Thanks for your great support so far!

Hi @kaan,

The connections you did look good, your search experience should work.

Having singleIndexHitsInteractor.connectController(self) is ok in your case

The initial idea is that you have a separate main Search ViewController containing all the interactors and a separate Hits ViewController:

class SearchViewController: UIViewController {
  var searcher: SingleIndexSearcher = ... 
  var queryInputInteractor = QueryInputInteractor()
  var singleIndexHitsInteractor: HitsInteractor<JSON> = .init(showItemsOnEmptyQuery: true)
}

class HitsViewController: UIViewController, HitsController {
  public weak var hitsSource: HitsInteractor<JSON>? 
}

Then you instantiate the main SearchViewController and connect HitsViewController to its HitsInteractor:

let searchViewController: SearchViewController = ...
let hitsViewController: HitsViewController = ...
searchViewController. singleIndexHitsInteractor.connectController(hitsViewController)

Of course, you are not obliged to follow the same approach, but this is how we recommend to implement it following the separation of concerns principle.