Skip to content

Search

This section explains how to implement online/offline search in iOS application.

Autocomplete

The Sygic Maps SDK for iOS includes a Search API which provides functionality to search and obtain more information about places in the real world. Note that offline search is supported when a data connection is unavailable, if the data required to perform the search has been previously downloaded. Geocoding APIs resolve a free-formatted text query to an SYGeoCoordinates, while reverse geocoding APIs resolve from an SYGeoCoordinates to geographic data.

Warning

Despite the fact that many SYSearch instances can coexist at the same time, please note that each instance leaves some internal resources until the whole Sygic Maps SDK is terminated.

Info

The offline/online search is no longer handled by the SYOnlineSession.onlineMapsEnabled switch.

Example

class DemoSearch {
    let type = SYSearchSessionType.offline
    let search = SYSearch()
    var session: SYSearchSession?
    var results = [SYSearchAutocompleteResult]()

    func autocomplete() {
        let session = prepareValidSession() // reuse existing session, if it's valid

        let request = SYSearchRequest(query: "airport", location: SYGeoCoordinate(latitude: 48.142596, longitude: 17.125206))
        session.autocomplete(request) { (results: [SYSearchAutocompleteResult]?, status: SYSearchStatus) in
            guard status == .success, let results = results else { /* handle error */ return }

            // results are ready
            self.results = results
            results.forEach { (result) in
                self.printAutocompleteResult(result)
            }
        }
    }

    func geocodeLocation(autocompleteResultIndex index: Int) {
        // for geocodeLocation, it must be the same session, which returned that exact autocomplete result

        guard let session = session, session.isValid else { /* handle error */ return }
        guard let autocompleteResult = (index >= 0 && index < results.count ? results[index] : nil) else { return }
        guard let locationId = autocompleteResult.locationId else { return }

        let request = SYGeocodeLocationRequest(locationId: locationId)
        session.finish(byRequestingGeocodeLocation: request) { (result: SYSearchGeocodingResult?, status: SYSearchStatus) in
            guard status == .success, let result = result else { /* handle error */ return }

            // detailed result is ready
            self.printDetailedResult(result)
        }
    }

    func geocode() {
        let session = prepareValidSession() // reuse existing session, if it's valid

        let request = SYSearchRequest(query: "airport", location: SYGeoCoordinate(latitude: 48.142596, longitude: 17.125206))
        session.finish(byRequestingGeocode: request) { (results: [SYSearchGeocodingResult]?, status: SYSearchStatus) in
            guard status == .success, let results = results else { /* handle error */ return }

            // detailed results are ready
            results.forEach { (result) in
                self.printDetailedResult(result)
            }
        }
    }

    func prepareValidSession() -> SYSearchSession {
        if let session = session, session.isValid {
            return session
        } else {
            let session = search.startSession(type)
            self.session = session
            return session
        }
    }

    func printAutocompleteResult(_ result: SYSearchAutocompleteResult) {
        let title = result.title?.value ?? ""
        print("Autocomplete: \(title), \(result.type.rawValue)")
    }

    func printDetailedResult(_ result: SYSearchGeocodingResult) {
        let title = result.title?.value ?? ""
        let lat = result.location?.latitude ?? 0
        let lon = result.location?.longitude ?? 0
        print("GeocodingResult: \(title), \(result.type.rawValue); \(lat),\(lon)")

        if let mapResult = result as? SYSearchMapResult {
            // mapResult provides more specific info
        } else if let favoriteResult = result as? SYSearchFavoriteResult {
            // favoriteResult provides more specific info
        } // else if let ... SYSearch...Result
    }
}

Places

You can also search places around a specific coordinate in a radius or in a Bounding Box. Here's an example on how to do it.

Info

To request more places with the same request, use SYSearchMorePlacesSession

extension DemoSearch  {

    func placesRequestLocation() -> SYSearchPlacesRequest {
        let location = SYGeoCoordinate(latitude: 48.142596, longitude: 17.125206)
        let request = SYSearchPlacesRequest(location: location, radius: 10000, tags: [SYPlaceCategoryPetrolStation, SYPlaceCategoryPharmacy])
        request.maxResultsCount = 22
        return request
    }

    func placesRequestBoundingBox() -> SYSearchPlacesRequest {
        let box = SYGeoBoundingBox(bottomLeft: SYGeoCoordinate(latitude: 48.139466, longitude: 17.103821),
                                topRight: SYGeoCoordinate(latitude: 48.149452, longitude: 17.118079))
        let request = SYSearchPlacesRequest(boundingBox: box, tags: [SYPlaceCategoryRestaurant])
        request.maxResultsCount = 14
        return request
    }

    func places() {
        let session = prepareValidSession() // reuse existing session, if it's valid

        let request = placesRequestLocation() //or placesRequestBoundingBox()

        session.finish(byRequestingPlaces: request) {
            (places: [SYPlace]?, morePlacesSession: SYSearchMorePlacesSession?, status: SYSearchStatus) in

            guard status == .success, let places = places else { /* handle error */ return }

            // place results are ready
            places.forEach { (place) in
                self.printPlace(place)
            }

            // morePlacesSession can be saved and then used to get more places for the same request
        }
    }

    func printPlace(_ place: SYPlace) {
        print("")
        print("Place name: \(place.link.name); cat: \(place.link.category); gps: \(place.link.coordinate)")
        place.details.forEach { (arg0) in
            let (key, value) = arg0
            print("Place detail: \(key): \(value)")
        }
    }
}

Reverse Geocoding

Applications developed with the Sygic Maps SDK for iOS can perform offline and online geocoding, which allows geocode and reverse geocode requests to be performed event without an active data connection.

class DemoReverseGeocoding {
    let search = SYReverseSearch()

    func reverseSearch() {
        let coordinate = SYGeoCoordinate(latitude: 48.146410, longitude: 17.138270)

        search.reverseSearch(with: coordinate, withFilter: nil) { (results: [SYReverseSearchResult]?, error) in
            guard let results = results else {
                print("SYReverseSearch error: \(String(describing: error))")
                return
            }
            results.forEach { $0.printDescription() }
        }
    }
}

extension SYReverseSearchResult {
    func printDescription() {
        let description = resultDescription
        print("""
            \nSYReverseSearchResult:
            country: \(description.countryIso)
            city: \(String(describing: description.city))
            street: \(String(describing: description.street))
            house number: \(String(describing: description.houseNumber))
            distance: \(distance)
            """)
    }
}