Open imrobbyrc opened 2 months ago
Can you show how your DataStack
is being initialized from UserViewModel.init()
?
It's showing up in your stack trace:
here's my UserVIewModel.init()
class UserViewModel: ObservableObject {
private let userPublisher = dataStack.publishList(From<Membership>().orderBy(.ascending(\.$id)))
private let cartPublisher = Omni.dataStack.publishList(From<Omni.Cart>().orderBy(.ascending(\.$storeCode)))
@ObjectState var user: ObjectSnapshot<Membership>?
@Published var progress: Double = 0
@Published var spendingToNextTier: Double = 0
@Published var membershipStatus: MembershipStatus = .member
init() {
_user = .init(userPublisher.snapshot.first)
progress = 0
spendingToNextTier = 0
userPublisher.addObserver(self, notifyInitial: true) { [weak self] publisher in
guard let self else { return }
let snapshot: ListSnapshot<Membership> = publisher.snapshot
guard let user = snapshot.first else {
self.progress = 0
self.spendingToNextTier = 0
self.membershipStatus = .member
return
}
self._user = .init(user)
let upgradeSpending = Double(user.upgradeSpending ?? 0)
let totalSpending = Double(user.totalSpending ?? 0)
let difference = upgradeSpending - totalSpending
self.progress = upgradeSpending == 0 ? 100 : (upgradeSpending - difference) / upgradeSpending * 100
self.spendingToNextTier = difference
self.membershipStatus = MembershipStatus(rawValue: user.membershipStatus ?? 100) ?? .member
} }
deinit {
userPublisher.removeObserver(self)
}
}
i got 3 variant of that crash
here's crashlytics trace crashlytics.zip
The problem is this line:
Since your DataStack
is initialized asynchronously, publishList()
is trying to start a fetch before your addStorage()
's completion is called. I would recommend that you defer initializing any publishers on the DataStack
before addStorage
has completed. That said, I wouldn't recommend converting it to a synchronous version (addStorageAndWait()
) either, as eventually you will have to handle migrations and convert them back to asynchronous again.
The problem is this line:
Since your
DataStack
is initialized asynchronously,publishList()
is trying to start a fetch before youraddStorage()
's completion is called. I would recommend that you defer initializing any publishers on theDataStack
beforeaddStorage
has completed. That said, I wouldn't recommend converting it to a synchronous version (addStorageAndWait()
) either, as eventually you will have to handle migrations and convert them back to asynchronous again.
hmm i think i already handle it in OnboardingViewController
.
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
Stamps.createDataStack {
dispatchGroup.leave()
}
dispatchGroup.enter()
Omni.createDataStack {
dispatchGroup.leave()
}
dispatchGroup.notify(queue: .main) {
guard dataStack != nil || Omni.dataStack != nil else {
print("Error: dataStack is not initialized")
return
}
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let mainTabBarController = storyboard.instantiateViewController(identifier: "MarugameTabbarViewController")
(UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.changeRootViewController(mainTabBarController)
}
I'm not sure when that OnboardingViewController
code is getting called, but your crash is from HomeViewController
→ UserViewModel
initialization. Try putting breakpoints and check whether the publishList
calls are called ahead of your addStorage
completion. Note that if you have an Storyboard set as an "Initial View Controller", that View Controller is likely to get initialized even before applicationDidFinishLaunching
I'm not sure when that
OnboardingViewController
code is getting called, but your crash is fromHomeViewController
→UserViewModel
initialization. Try putting breakpoints and check whether thepublishList
calls are called ahead of youraddStorage
completion. Note that if you have an Storyboard set as an "Initial View Controller", that View Controller is likely to get initialized even beforeapplicationDidFinishLaunching
try to breakpoint in publishList
with print in appdelete and scene delete, it called after my print statement. do you have idea how i can handle addStorage
? i use OnboardingViewController
to handle addStorage
hi @JohnEstropia , i got a reason why it crash, the initialize dataStack is complete but persistentStore is empty, you can see this log, do you know why it still empty? it's crash when the device in lock state
do you know why it still empty?
It's empty because addStorage()
is not complete yet.
Add a breakpoint on the onComplete()
line here:
Anything that accesses dataStack.*
methods before that onComplete()
runs is your culprit.
do you know why it still empty?
It's empty because
addStorage()
is not complete yet.Add a breakpoint on the
onComplete()
line here:Anything that accesses
dataStack.*
methods before thatonComplete()
runs is your culprit.
thanks for reply @JohnEstropia, but i use DispatchGroup()
to handle the flow
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
Omni.createDataStack {
dispatchGroup.leave()
}
dispatchGroup.enter()
Stamps.createDataStack {
dispatchGroup.leave()
}
dispatchGroup.notify(queue: .main) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let mainTabBarController = storyboard.instantiateViewController(identifier: "MarugameTabbarViewController")
(UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.changeRootViewController(mainTabBarController)
if Membership.isAuthenticated, !Defaults.deviceToken.isEmpty {
registerPushNotificationKey()
}
Session.setCrashlyticsData()
UIApplication.shared.registerForRemoteNotifications()
}
}
onComplete()
metho should call dispatchGroup.leave()
and will notify dispatchGroup
, right?
i got this error on corestore callback @JohnEstropia
Sorry if I wasn't clear. The breakpoints are to find the order of events happening in your app. You'd need to compare which of the following is hit first:
addStorage()
method's onComplete()
callbackHomeViewController.promotionPublisher
let
stored property (I'm assuming Omni.dataStack
is the same as the global var dataStack
declared in DataStack.swift
)UserViewModel.init()
, specifically let userPublisher
and let cartPublisher
dataStack
that happens right after launchSorry, scratch that. I just noticed your error in the last screenshot is in the completion
closure itself. The error code 259
implies the file already exists. Do you know where/when this file is being created?
Sorry, scratch that. I just noticed your error in the last screenshot is in the
completion
closure itself. The error code259
implies the file already exists. Do you know where/when this file is being created?
the file should be exists because if i open the apps normaly it will be fine, the problem is when the apps backgroundly launched by push notification in locked state
I see. CoreStore doesn't set any NSFileProtectionKey
or NSPersistentStoreFileProtectionKey
explicitly, so the default will be NSFileProtectionCompleteUntilFirstUserAuthentication
. Does the same issue happen if the notifications arrive in the lockscreen AFTER the first device passcode entry?
I see. CoreStore doesn't set any
NSFileProtectionKey
orNSPersistentStoreFileProtectionKey
explicitly, so the default will beNSFileProtectionCompleteUntilFirstUserAuthentication
. Does the same issue happen if the notifications arrive in the lockscreen AFTER the first device passcode entry?
yes, as long as the device is locked it will be fail to initiate datastack
how i can set data NSPersistentStoreFileProtectionKey
and NSFileProtectionKey
? i see in source code it only let variable
I'll add a way to set these flags. In the meantime, if you need it sooner you might want to fork CoreStore temporarily and add the necessary flags in the code you screenshot above
I'll add a way to set these flags. In the meantime, if you need it sooner you might want to fork CoreStore temporarily and add the necessary flags in the code you screenshot above
yes i need it sooner as my crashlytics going down 😅 thankyou for your help @JohnEstropia
Another approach would be to present a separate notification when the device has not been authenticated. If your users' data are loaded from that store, you might want to keep them encrypted for security.
Regardless, I'll notify this thread after I update the SDK
Another approach would be to present a separate notification when the device has not been authenticated. If your users' data are loaded from that store, you might want to keep them encrypted for security.
Regardless, I'll notify this thread after I update the SDK
i think i will wait for SDK. thanks @JohnEstropia
hi sorry, any update on this bro @JohnEstropia ?
@imrobbyrc Since I cannot promise a release date on this update, please fork and implement the protection flags on your side for now. While this looks like an easy fix for some simple use cases, supporting it on the API level means CoreStore should be able to handle any failures related to access protections so I'd like to do it correctly for common use cases (ex: deeplinks from push notifications like yours, background fetches etc.)
Crashlog: testflight_feedback.zip
the is intermittent, when the device recieved notifcation but apps is not running, it will crash. it doesnt happend when apps open or in background state.
my apps flow is,
OnBoardingViewController
is the main viewcontroller where apps open, its setup from datastack after that it'll setupTabBar like code above, here's some code for NotificationServiceExtension and other important codehope you can help me with this @JohnEstropia
notification extension
Datastack for notification extension
delegate for notification
my main datastack
datastack
Homeviewcontroller where the crash is