Part- 3: My Journey with Map Search in the Community App


Adding Donation Pickup Points with Maps
When I was building the Donation Pickup Point feature in my first community app, I knew I needed to integrate a map. The idea was simple:
A donor should be able to choose a pickup location.
Other users should see it on the map easily.
So I turned to MapKit, Apple’s native framework for maps. It worked beautifully for showing maps and pins. But when it came to searching places, I quickly hit a wall:
MapKit’s search results were poor and limited.
Many local areas (which were important for donation pickup points) simply didn’t appear.
This was frustrating because the app relied heavily on accurate search.
At first, I thought about Google Places API, it’s reliable and accurate worldwide. But it came with a problem: it’s expensive, and for an early-stage experimental project, I couldn’t afford that.
Nominatim API as Alternative
This was also my first work with Map integration in an app, and I quickly realized MapKit’s built-in search wasn’t enough. The results were too limited, and many local areas (needed for donation pickup points) were missing.
That’s when I found Nominatim Search. It’s free, open-source, and much better for covering smaller/local places.
Here’s how I used it:
MapKit → for rendering maps and dropping pins.
Nominatim API → for handling search queries and returning better location results.
A custom list → to show search results, from which users could select their pickup point.
Introducing Nominatim API & NominatimPlace
What it is: A free, open-source geocoding/search API powered by OpenStreetMap.
What it does: Turns a text query like
"Rangpur Medical College"
into latitude & longitude, or finds places nearby.Why it’s great: Free, covers smaller/local areas, perfect for MVPs or experiments.
To use it in Swift, we create a model to hold the results called NominatimPlace
. This is just a custom struct that matches the JSON returned by Nominatim:
struct NominatimPlace : Decodable, Hashable {
let place_id: Int
let display_name: String
let lat: String
let lon: String
var coordinate: CLLocationCoordinate2D {
CLLocationCoordinate2D(latitude: Double(lat) ?? 0, longitude: Double(lon) ?? 0)
}
}
Breaking it down:
place_id
→ unique ID for the place from Nominatim.display_name
→ human-readable name of the place (e.g., “Dhaka, Bangladesh”).lat & lon
→ latitude and longitude as strings (returned by the API).coordinate
→ convertslat
andlon
intoCLLocationCoordinate2D
so MapKit can use it to drop pins.
Searching Places with Nominatim API in Swift
This function handles searching places using Nominatim API and returns a list of NominatimPlace
objects that you can use in your app:
func nominatimSearch(query: String) async throws -> [NominatimPlace] {
// Prepare URL with query and JSON format
let escapedQuery = query.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "" //prepares a user’s search input
let urlString = "https://nominatim.openstreetmap.org/search?q=\(escapedQuery)&format=json&addressdetails=1&limit=10" //return search result in JSON
guard let url = URL(string: urlString) else {
return []
}
// Create request with custom User-Agent as required by Nominatim's usage policy
var request = URLRequest(url: url)
request.setValue("MapMonitoring - nusratjahan6169@gmail.com", forHTTPHeaderField: "User-Agent")
let (data, _) = try await URLSession.shared.data(for: request)
let places = try JSONDecoder().decode([NominatimPlace].self, from: data)
return places
}
Step-by-step Explanation:
Escape the query:
addingPercentEncoding
ensures that spaces or special characters in the user’s search input are safe for URLs.Build the URL:
We create the Nominatim search URL with the query, asking for JSON format, address details, and limiting results to 10.Check URL validity:
If URL creation fails, the function safely returns an empty list.Add User-Agent header:
Nominatim requires a custom User-Agent in the request. This identifies your app to the service.Fetch data asynchronously:
UsingURLSession.shared.data
(for:)
with async/await calls the API and waits for the response.Decode JSON into Swift objects:
JSONDecoder
converts the returned JSON into[NominatimPlace]
, which you can now use in SwiftUI or MapKit.
Conclusion – My First Map Integration Journey
As someone new to Map integration, this was my first real attempt at connecting search, maps, and user interaction in an app. Along the way, I stumbled over:
Limited search results in MapKit
Figuring out a way to use free alternatives instead of expensive APIs
Converting API responses into something SwiftUI and MapKit can understand
Using Nominatim API taught me that for MVPs or experimental projects, free and open-source tools can work really well, even if they aren’t perfect.
A note to the community: If you’ve tried a better or smarter free approach for location search and map integration, I’d love to hear it . Sharing tips helps all of us learn faster!
Subscribe to my newsletter
Read articles from Tabassum Akter Nusrat directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Tabassum Akter Nusrat
Tabassum Akter Nusrat
Former Android dev at Samsung R&D, now diving deep into iOS development. Writing daily about Swift Concurrency, SwiftUI, and the journey of building real-world apps. Passionate about clean architecture, mental health tech, and learning in public.