英文:
Realm opens 4 times on Login
问题
只有以下部分代码会多次打印日志 "INFO: [REALM] Realm opened: /var/mobile/":
self.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
// ...
})
}else{
print("login failed")
}
}
这可能是因为您在 repo.login
的回调中调用了 self.repo.getUserProfile
,而 watch
方法似乎会导致 Realm 多次打开。您可以尝试将这两个调用分开,以避免 Realm 多次打开。
此外,确保您在 repo.getUserProfile
方法内关闭 Realm,以防止不必要的 Realm 打开。确保您在完成 Realm 操作后调用 realm.close()
。
请注意,这只是基于您提供的代码片段的猜测,更详细的调试和分析可能需要检查完整的代码和 Realm 数据库配置。
英文:
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
答案1
得分: 2
以下是您要翻译的内容:
-
There is a very simple explanation why realm opens several times:
Realm.open
call is insideRealmRepo
instance and you are creating multipleRealmRepo
instances. -
For instance SwiftUI recreates
RealmRepo
with every state change. Also other views e.g.HomeView
creates its ownRealmRepo
and so on. -
There are a lot of different ways to fix it. Here is some of them:
Make your RealmRepo
object
Just change class RealmRepo
to object RealmRepo
. That will make your RealmRepo
a singleton in your iOS code you can access it like this:
var repo = RealmRepo.shared
Use EnvironmentObject
There is a simple Dependency Injection mechanism in SwiftUI that can help you use a single instance of RealmRepo.
In your iOSApp.swift
:
import SwiftUI
@main
struct iOSApp: App {
@StateObject var repo = RealmRepo()
var body: some Scene {
WindowGroup {
LoginScreenView()
.environmentObject(repo)
}
}
}
and in all child views Login
, HomeView
, etc. use:
@EnvironmentObject var repo: RealmRepo
and do not create new instances.
More about @EnvironmentObject
you can read here
Use some DI frameworks
You can use some DI frameworks, e.g. Koin and specify RealmRepo
as a singleton when injected into the iOS app.
Refactor RealmRepo
You can change how realm
field is initialized in RealmRepo
. For example, you can extract logic that opens Realm in a singleton:
class RealmRepo {
// ...
private val appService by lazy {
RealmHolder.appService
}
private val realm by lazy {
RealmHolder.realm
}
// ...
}
object RealmHolder {
private val schemaClass = set of(UserInfo::class, SessionInfo::class, ConferenceInfo::class)
val appService by lazy {
val appConfiguration =
AppConfiguration.Builder(appId = "rconfernce-vkrny").log(LogLevel.ALL).build()
App.create(appConfiguration)
}
val realm by lazy {
val user = appService.currentUser!!
val config =
SyncConfiguration.Builder(user, schemaClass).name("conferenceInfo").schemaVersion(1)
.initialSubscriptions { realm ->
add(realm.query<UserInfo>(), name = "user info", updateExisting = true)
add(realm.query<SessionInfo>(), name = "session info", updateExisting = true)
add(
realm.query<ConferenceInfo>(),
name = "conference info",
updateExisting = true
)
}.waitForInitialRemoteData().build()
Realm.open(config)
}
}
英文:
There is a very simple explanation why realm opens several time: Realm.open
call is inside RealmRepo
instance and you are creating multiple RealmRepo
instances.
For instance SwiftUI recreates RealmRepo
with every state change. Also other views e.g. HomeView
creates its own RealmRepo
and so on.
There are a lot of different ways to fix it. Here is some of them:
Make your RealmRepo
object
Just change class RealmRepo
to object RealmRepo
. That will make your RealmRepo
a singleton in your iOS code you can access it like this:
var repo = RealmRepo.shared
Use EnvironmentObject
There is a simple Dependency Injection mechanism in SwiftUI that can help you use single instance of RealmRepo.
In your iOSApp.swift
:
import SwiftUI
@main
struct iOSApp: App {
@StateObject var repo = RealmRepo()
var body: some Scene {
WindowGroup {
LoginScreenView()
.environmentObject(repo)
}
}
}
and in all child views Login
, HomeView
, etc. use:
@EnvironmentObject var repo: RealmRepo
and do not create new instances.
More about @EnvironmentObject
you can read here
Use some DI frameworks
You can use some DI frameworks, e.g. Koin and specify RealmRepo
as singleton where when inject in iOS app.
Refactor RealmRepo
You can change how realm
field initialized in RealmRepo
. For example you can extract logic that opens Realm in a singleton:
class RealmRepo {
// ...
private val appService by lazy {
RealmHolder.appService
}
private val realm by lazy {
RealmHolder.realm
}
// ...
}
object RealmHolder {
private val schemaClass = setOf(UserInfo::class, SessionInfo::class, ConferenceInfo::class)
val appService by lazy {
val appConfiguration =
AppConfiguration.Builder(appId = "rconfernce-vkrny").log(LogLevel.ALL).build()
App.create(appConfiguration)
}
val realm by lazy {
val user = appService.currentUser!!
val config =
SyncConfiguration.Builder(user, schemaClass).name("conferenceInfo").schemaVersion(1)
.initialSubscriptions { realm ->
add(realm.query<UserInfo>(), name = "user info", updateExisting = true)
add(realm.query<SessionInfo>(), name = "session info", updateExisting = true)
add(
realm.query<ConferenceInfo>(),
name = "conference info",
updateExisting = true
)
}.waitForInitialRemoteData().build()
Realm.open(config)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论