Using Maps and Location Data in Your SwiftUI (+Realm) App
Rate this tutorial
If you only need to support iOS14 and later, then you can forget most of that messy code 😊. If you need to support iOS13—sorry, you need to go the O-FISH route!
This article shows you how to embed Apple Maps into your app views using Mapkit's Map view. We'll then look at how you can fetch the user's current location—with their permission, of course!
To begin, let's create a simple view that displays a map, the coordinates of the center of that map, and the zoom level:
With Mapkit and SwiftUI, this only takes a few lines of code:
showsUserLocationwon't work unless the user has already given the app permission to use their location—we'll get to that.
regionis initialized to a starting location, but it's updated by the
Mapview as the user scrolls and zooms in and out.
Pins can be added to a map in the form of "annotations." Let's start with a single pin:
We can now create an array of
We then pass
MapViewand indicate that we want a
MapMarkerat the contained coordinates:
That gives us the result we wanted.
What if we want multiple pins? Not a problem. Just add more
MyAnnotationIteminstances to the array.
All of the pins will be the same default color. But, what if we want different colored pins? It's simple to extend our code to produce this:
Firstly, we need to extend
MyAnnotationItemto include an optional
colorif it's been defined and "red" if not:
In our sample data, we can now choose to provide a color for each annotation:
MapViewcan then use the
If you get bored of pins, you can use
MapAnnotationto use any view you like for your annotations:
This is the result:
You could also include the name of the system image to use with each annotation.
Apple is pretty vocal about respecting the privacy of their users, and so it shouldn't be a shock that your app will have to request permission before being able to access a user's location.
The first step is to add a key-value pair to your Xcode project to indicate that the app may request permission to access the user's location, and what text should be displayed in the alert. You can add the pair to the "Info.plist" file:
Once that setting has been added, the user should see an alert the first time that the app attempts to access their current location:
While Mapkit has made maps simple and native in SwiftUI, the same can't be said for location data.
Once added, you can access the user's location with this simple call:
Realm doesn't have a native type for a geographic location, and so it's up to us how we choose to store it in a Realm Object. That is, unless we want to synchronize the data to MongoDB Atlas using Device Sync, and go on to use MongoDB's geospatial functionality.
To make the best use of the location data in Atlas, we need to add a to the field (which we’ll see how to do soon.) That means storing the location in a . Not all options will work with Atlas Device Sync (e.g., it's not guaranteed that attributes will appear in the same order in your Realm Object and the synced Atlas document). The most robust approach is to use an array where the first element is longitude and the second is latitude:
locationarray that's passed to that initializer is formed like this:
This is a document that's been created from a synced Realm
From the Atlas UI, select the "Indexes" tab for your collection and click "CREATE INDEX":
You should then configure a
Most chat messages won't include the user's location and so I set the
sparseoption for efficiency.
Note that you'll get an error message if your ChatMessage collection contains any documents where the value in the location attribute isn't in a valid geospatial format.
Atlas will then build the index. This will be very quick, unless you already have a huge number of documents containing the location field. Once complete, you can move onto the next section.
The first step is to click the "Add Data Source" button:
Select your Atlas cluster:
Click “Finish.” You’ll be taken to the default Dashboards view, which is empty for now. Click "Add Dashboard":
In your new dashboard, click "ADD CHART":
Configure your chart as shown here by:
- Setting the chart type to "Geospatial" and the sub-type to "Scatter."
- Dragging the "location" attribute to the coordinates box.
- Dragging the "author" field to the "Color" box.
SwiftUI makes it easy to embed Apple Maps in your SwiftUI apps. As with most Apple frameworks, there are extra maps features available if you break out from SwiftUI, but I'd suggest that the simplicity of working with SwiftUI is enough incentive for you to avoid that unless you have a compelling reason.
Accessing location information from within SwiftUI still feels a bit of a hack, but in reality, you cut and paste the helper code once, and then you're good to go.
By storing the location as a
[longitude, latitude]array (
List) in your Realm database, it's simple to sync it with MongoDB Atlas. Once in Atlas, you have the full power of MongoDB's geospatial functionality to work your location data.