I have a app that checks when loggin in the type of user, to know where to navigate.
Whenver I do the login, in the logs, the realm will open 4 times.
My login View:
struct LoginView: View {
@State var userId : String = ""
@State var password : String = ""
@State var goToNextScreen : Int? = nil
@State var myIsUser = false
@State var myUser = UserInfo()
var repo = RealmRepo()
var body: some View {
NavigationView{
VStack(){
TextField("Username", text: $userId)
TextField("Password", text: $password)
Button("Login"){
repo.login(email: $userId.wrappedValue, password: $password.wrappedValue) { user, error in
if(user != nil){
self.repo.getUserProfile(userId: user?.id as! String).watch(block: {items in
self.myUser = items as! UserInfo
if(self.myUser.typeOfUser != true){
print("this user type 1")
UserDefaults.standard.set(false, forKey: "isUser")
UserDefaults.standard.set(true, forKey: "isLogin")
myIsUser=false
}else{
print("this is user type2")
UserDefaults.standard.set(true, forKey: "isUser")
UserDefaults.standard.set(true, forKey: "isLogin")
myIsUser=true
}
goToNextScreen=1
})
}else{
print("login failed")
}
}
}
NavigationLink(destination: myIsUser ? AnyView(View1().navigationBarHidden(true)) : AnyView(View2().navigationBarHidden(true)) , tag: 1, selection: $goToNextScreen){
EmptyView()
}
}
}
}
}
Only this part of code will print 4 times the log: INFO: [REALM] Realm opened: /var/mobile/
This part just checks the login and goes to a view.
How is this possible?
Is it because the the login block? Should I make the login and getUserProfile calls in a different way?
The repo.login method:
suspend fun login(email: String, password: String): User {
return appService.login(Credentials.emailPassword(email, password))
}
The repo.getUserProfile() that will return the type of the user:
fun getUserProfile(userId: String): CommonFlow<UserInfo?> {
val user = realm.query<UserInfo>("_id = $0", userId).asFlow().map {
it.list.firstOrNull()
}.asCommonFlow()
return user
}
enter code here
I ve uploaded a reproduction scenario: tmpfiles.org/1031395/mongo-conference-master3.zip
It is the same as the repository from mongodb github.com/mongodb-developer/mongo-conference, just with the getUserProfile changed with return CommonFlow
There is a very simple explanation why realm opens several time:
Realm.opencall is insideRealmRepoinstance and you are creating multipleRealmRepoinstances.For instance SwiftUI recreates
RealmRepowith every state change. Also other views e.g.HomeViewcreates its ownRealmRepoand so on.There are a lot of different ways to fix it. Here is some of them:
Make your
RealmRepoobjectJust change
class RealmRepotoobject RealmRepo. That will make yourRealmRepoa singleton in your iOS code you can access it like this:Use
EnvironmentObjectThere is a simple Dependency Injection mechanism in SwiftUI that can help you use single instance of RealmRepo.
In your
iOSApp.swift:and in all child views
Login,HomeView, etc. use:and do not create new instances.
More about
@EnvironmentObjectyou can read hereUse some DI frameworks
You can use some DI frameworks, e.g. Koin and specify
RealmRepoas singleton where when inject in iOS app.Refactor
RealmRepoYou can change how
realmfield initialized inRealmRepo. For example you can extract logic that opens Realm in a singleton: