Synced Realm on iOS with SwiftUI using Sign-in with Apple for Authentication
Tackling
AttributeGraph precondition failure: setting value during update
using Realm in SwiftUISynced Realm on iOS with SwiftUI using Sign-in with Apple for Authentication
Some apps store sensitive user information that requires authorized access. For example, an app may store a user’s first and last name which should not be accessed by any other user. As such, these apps need to integrate with authorized data storage. On iOS, two commonly employed technologies for authentication and authorized data storage are Sign-in with Apple and Realm, respectively.
Sign-in with Apple
Apple’s mechanism provides seamless authentication for users of third-party apps and websites on iOS. Using their existing Apple ID, users can sign up for an app or a website without verifying their email address or creating a new password.
As developers, Apple allows us to implement Sign-in with Apple through the Authentication Services framework. In SwiftUI, we simply combine this framework with a SignInWithAppleButton
to create the corresponding view. Everything else is conveniently handled by Apple and SwiftUI.
Realm
Realm is an ACID-compliant mobile database by MongoDB that features mobile-to-cloud synchronization. The storage technology is backed by MongoDB Atlas and is available for programming languages and frameworks including Swift and SwiftUI. Complementing the declarative nature of SwiftUI, Realm enables the developer to subscribe to data changes from the UI for a reactive user experience.
Integration
To be able to use the two technologies in our iOS app, we start by integrating Realm. For the app.swift
, we initialize the RealmSwift.App
using the Realm’s ID (which can be retrieved from the corresponding MongoDB project) for later use throughout our app:
Passing RealmSwift.App
’s instance to WelcomeView
where we delegate to SplashScreen
or LoginView
based on the user’s login status showing the splash screen or allowing the user to log in, respectively:
In particular, LoginView
contains the logic for Sign-in with Apple, and SplashScreen
loads the Realm. As mentioned at the beginning, using Sign-in with Apple in SwiftUI is fairly straightforward:
While Sign-in with Apple and Realm are two separate technologies, the latter easily allows to integrate with the former. Simply providing the identity token of the Apple ID in question to Realm is enough to carry through the authentication as we can observe in login()
. For SplashScreen
, the implementation is similarly straightforward:
At this point in the implementation, we no longer have to take care of Sign-in with Apple since the user is already signed in. Likewise, the user is already logged into the Realm such that we only need to connect to the Realm for synchronization. Luckily, the Swift SDK provides a property wrapper, i.e., @AsyncOpen
, that abstracts all the connection logic. We do not need to provide a partitionValue
since the partition value is already supplied as an environmental variable in WelcomeView.swift
. Finally, utilize the resulting property asyncOpen
to react to the connection state where we show the MainView()
after the Realm is opened.
The implementation that we have outlined above includes asynchronous partition-based synchronization with Atlas App Services. We can utilize the synchronized Realm to provide cross-device synchronization as a feature or develop a cross-platform application (there is even a Web SDK for Realm!) with a unified backend. If we were to use Realm on iOS as a solution for local storage only, we would leave out the initialization of RealmSwift.App
, remove login()
, and remove @AsyncOpen
.