Hi,
I’ve been successfully using the InstantSearchClient
library in my iOS project for years now. Yesterday I finally updated my pods and now AlgoilaSearchClient
is the updated library. The issue is there have been several Algolia changes such as Query
initializers, data types, callbacks, etc. and several errors have appeared. I placed ERROR next to them in the newer code.
I was wondering if anyone can help update my older InstantSearchClient
code to the newer AlgoilaSearchClient
code. I actually got the code from the functions from an Algolia tutorial sample post years ago. It worked great!
Older Code:
import InstantSearchClient
var datasource = [DataModel]()
var algoliaIndex: InstantSearchClient.Index!
let query = Query()
var searchId = 0
let displayedSearchId = -1
var loadedPage: UInt = 0
var nbPages: UInt = 0
func setAlgoliaAPI() {
let apiClient = Client(appID: "...", apiKey: "...")
algoliaIndex = apiClient.index(withName: "home")
query.hitsPerPage = 15
query.attributesToRetrieve = ["...", "..."]
query.restrictSearchableAttributes = ["...", "..."]
}
func updateSearchResults(for searchController: UISearchController) {
query.query = searchController.searchBar.text
let curSearchId = searchId
algoliaIndex.search(query: query) { [weak self] (data, error) in
guard let weakSelf = self else { return }
if let error = error {
print(error.localizedDescription)
return
}
if curSearchId <= weakSelf.displayedSearchId { return }
// Decode JSON
guard let hits = data!["hits"] as? [[String: Any]] else { return }
guard let nbPages = data!["nbPages"] as? UInt else { return }
self?.nbPages = nbPages
var tmp = [DataModel]()
for hit in hits {
if let entry = hit.keys.first(where: { $0.lowercased().contains("account") }) {
if let dict = hit[entry] as? [String: AnyObject] {
tmp.append(DataModel(json: dict))
}
}
print(hit)
}
guard let safeText = searchController.searchBar.text else { return }
if safeText.trimmingCharacters(in: safeText.whitespace) == "" {
self?.datasource.removeAll()
} else {
//Reload view with the new data
self?.datasource = tmp
}
self?.tableView.reloadData()
})
searchId += 1
}
func loadMore() {
if loadedPage + 1 >= nbPages {
return // All pages already loaded
}
let nextQuery = Query(copy: query)
nextQuery.page = loadedPage + 1
algoliaIndex.search(query: nextQuery) { [weak self] (data , error) in
if let error = error {
print(error.localizedDescription)
return
}
if nextQuery.query != self?.query.query {
return // Query has changed
}
guard let safeNextQueryPage = nextQuery.page else { return }
self?.loadedPage = safeNextQueryPage as UInt
if let data = data {
let json = JSON(data)
let hits: [JSON] = json["hits"].arrayValue
var tmp = [DataModel]()
print("\nhits_count...\(hits.count)\n")
for record in hits {
guard let hit = record.dictionaryObject else { continue }
if let entry = hit.keys.first(where: { $0.lowercased().contains("account") }) {
if let dict = hit[entry] as? [String: AnyObject] {
tmp.append(DataModel(json: dict))
}
}
}
// Display the new loaded page
self?.datasource.append(contentsOf: tmp)
self?.tableView.reloadData()
}
})
}
Newer Code:
import AlgoliaSearchClient
var algoliaIndex: AlgoliaSearchClient.Index!
var query = Query()
var searchId = 0
let displayedSearchId = -1
var loadedPage: Int = 0
var nbPages: UInt = 0
func setAlgoliaAPI() {
let apiClient = SearchClient(appID: "...", apiKey: "...")
algoliaIndex = apiClient.index(withName: "home")
// ...
}
func updateSearchResults(for searchController: UISearchController) {
query.query = searchController.searchBar.text
let curSearchId = searchId
algoliaIndex.search(query: query) { [weak self](result) in
guard let weakSelf = self else { return }
switch result {
case .failure(let error):
print(error.localizedDescription)
case .success(let searchResponse):
if curSearchId <= weakSelf.displayedSearchId {
return // Newest query already displayed or error
}
// Decode JSON
guard let hits = searchResponse["hits"] as? [[String: Any]] else { return } // ERROR - Value of type 'SearchResponse' has no subscripts
guard let nbPages = searchResponse["nbPages"] as? UInt else { return } // ERROR - Value of type 'SearchResponse' has no subscripts
self?.nbPages = nbPages
var tmp = [DataModel]()
for hit in hits {
if let entry = hit.keys.first(where: { $0.lowercased().contains("account") }) {
if let dict = hit[entry] as? [String: AnyObject] {
tmp.append(DataModel(json: dict))
}
}
}
guard let safeText = searchController.searchBar.text else { return }
if safeText.trimmingCharacters(in: safeSelf.whitespace) == "" {
self?.datasource.removeAll()
} else {
//Reload view with the new data
self?.datasource = tmp
}
self?.tableView.reloadData()
}
}
searchId += 1
}
func loadMore() {
if loadedPage + 1 >= nbPages {
return // All pages already loaded
}
let nextQuery = Query(copy: query) // ERROR - No exact matches in call to initializer
nextQuery.page = loadedPage + 1
algoliaIndex.search(query: nextQuery) { [weak self](result) in
switch result {
case .failure(let error):
print(error.localizedDescription)
case .success(let data):
if nextQuery.query != self?.query.query {
return // Query has changed
}
guard let safeNextQueryPage = nextQuery.page else { return }
self?.loadedPage = safeNextQueryPage as Int
if let data = data { // ERROR - Initializer for conditional binding must have Optional type, not 'SearchResponse'
let json = JSON(data) // ERROR - Call can throw, but it is not marked with 'try' and the error is not handled
let hits: [JSON] = json["hits"].arrayValue // ERROR - JSON' is ambiguous for type lookup in this context
var tmp = [DataModel]()
print("\nhits_count...\(hits.count)\n")
for record in hits {
guard let hit = record.dictionaryObject else { continue }
if let entry = hit.keys.first(where: { $0.lowercased().contains("account") }) {
if let dict = hit[entry] as? [String: AnyObject] {
tmp.append(DataModel(json: dict))
}
}
}
// Display the new loaded page
self?.datasource.append(contentsOf: tmp)
self?.tableView.reloadData()
}
}
}
}
DataModel:
class DataModel {
// ...
init(json: [String: Any]) {
// ...
}
}