Skip to main content

Search Category

Last updated: March 13, 2026 | 4 minutes read

This example demonstrates how to use GEMKit in a UIKit application to search for Landmarks in a specific category.

Check the full implementation on GitHub.

Initial screen
Categories List
Gas Station Category Search

Map Display and Search Button

The following code outlines the map view with a search button in the navigation bar. Tapping the search button will navigate to a list of categories:

ViewController.swiftView on GitHub
class ViewController: UIViewController {

var mapViewController: MapViewController?

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.

if let navigationController = self.navigationController {

let appearance = navigationController.navigationBar.standardAppearance

navigationController.navigationBar.scrollEdgeAppearance = appearance
}

self.createMapView()

self.mapViewController!.startRender()

self.addSearchButton()
}

// MARK: - Map View

func createMapView() {

self.mapViewController = MapViewController.init()
self.mapViewController!.view.backgroundColor = UIColor.systemBackground

self.addChild(self.mapViewController!)
self.view.addSubview(self.mapViewController!.view)
self.mapViewController!.didMove(toParent: self)

self.mapViewController?.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.mapViewController!.view.topAnchor.constraint(equalTo: self.view.topAnchor),
self.mapViewController!.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
self.mapViewController!.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
self.mapViewController!.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)
])
}

// MARK: - Search

func addSearchButton() {

let barButton = UIBarButtonItem.init(
image: UIImage.init(systemName: "magnifyingglass"), style: .done, target: self, action: #selector(searchButton(item:)))

self.navigationItem.rightBarButtonItems = [barButton]
}

@objc func searchButton(item: UIBarButtonItem) {

let poiListViewController = PoiCategoriesViewController.init()

self.navigationController?.pushViewController(poiListViewController, animated: true)
}
}

The code for PoiCategoriesViewController prepares a list of categories and performs a search when a category is selected. The search results are then highlighted on the map:

PoiCategoriesViewController.swiftView on GitHub
class PoiCategoriesViewController: UITableViewController {

let searchContext = SearchContext.init()

let categoriesContext = GenericCategoriesContext.init()

var categoriesList: [LandmarkCategoryObject] = []

deinit {

NSLog("PoiCategoriesViewController: deinit")
}

// MARK: - Life Cycle

override func viewDidLoad() {

super.viewDidLoad()

self.title = "Poi Categories"
self.navigationItem.largeTitleDisplayMode = .never

self.view.backgroundColor = UIColor.systemBackground

self.searchContext.setMaxMatches(40)
self.searchContext.setSearchMapPOIs(true)

self.refreshList()
}

// MARK: - Refresh

func refreshList() {

self.categoriesList = self.categoriesContext.getCategories()

self.tableView.reloadData()
}

// MARK: - UITableViewData

override func numberOfSections(in tableView: UITableView) -> Int {

return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

let rows = self.categoriesList.count

return rows
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

let identifier = "defaultCellId"

var cell = tableView.dequeueReusableCell(withIdentifier: identifier)

if cell == nil {

cell = UITableViewCell.init(style: .subtitle, reuseIdentifier: identifier)

cell!.textLabel!.numberOfLines = 0
cell!.detailTextLabel!.numberOfLines = 0
}

self.setupText(tableView: tableView, cell: cell!, indexPath: indexPath)

self.setupImage(tableView: tableView, cell: cell!, indexPath: indexPath)

return cell!
}

func setupText(tableView: UITableView, cell: UITableViewCell, indexPath: IndexPath) {

let category = self.categoriesList[indexPath.row]

let text = category.getName()
cell.textLabel?.text = text

let description = "id: " + String(category.getIdentifier())
cell.detailTextLabel?.text = description
}

func setupImage(tableView: UITableView, cell: UITableViewCell, indexPath: IndexPath) {

let scale = UIScreen.main.scale
let size = CGSize.init(width: 60.0 * scale, height: 60.0 * scale)

let category = self.categoriesList[indexPath.row]

if let image = category.getImage(size) {

cell.imageView?.image = image
cell.imageView?.layer.shadowOpacity = 0.8
cell.imageView?.layer.shadowColor = UIColor.lightGray.cgColor

} else {

cell.imageView?.image = nil
cell.imageView?.layer.shadowOpacity = 0
cell.imageView?.layer.shadowColor = nil
}
}

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return nil
}

override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

tableView.deselectRow(at: indexPath, animated: true)

let category = self.categoriesList[indexPath.row]

let success = self.searchContext.setCategory(category)

guard success == true else {
return
}

if let viewController = self.navigationController?.viewControllers.first as? ViewController {

self.navigationController?.popViewController(animated: true)

if let mapViewController = viewController.mapViewController {

let location = CoordinatesObject.coordinates(withLatitude: 48.840827, longitude: 2.371899)

mapViewController.removeHighlights()

mapViewController.center(onCoordinates: location, zoomLevel: 60, animationDuration: 1200)

self.searchContext.searchAround(withLocation: location) { (results: [LandmarkObject]) in

let settings = HighlightRenderSettings.init()

mapViewController.presentHighlights(results, settings: settings)
}
}
}
}
}