Reputation: 35
I am getting the following error around 20% of the time I try to create an account: Can someone please help me in diagnosing the issue please
Crashed: com.apple.main-thread EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x0000000000000010
Crashed: com.apple.main-thread
0 libobjc.A.dylib 0x2820 objc_msgSend + 32
1 UIKitCore 0x2004a4 -[UIViewController dealloc] + 772
2 UIKitCore 0x1fe0cc -[UINavigationController dealloc] + 308
3 UIKitCore 0x486bbc -[_UISplitViewControllerColumnContents .cxx_destruct] + 44
4 libobjc.A.dylib 0x20a4 object_cxxDestructFromClass(objc_object*, objc_class*) + 116
5 libobjc.A.dylib 0x6e00 objc_destructInstance + 80
6 libobjc.A.dylib 0x104fc _objc_rootDealloc + 80
7 CoreFoundation 0x2a26c cow_cleanup + 168
8 CoreFoundation 0x62538 -[__NSDictionaryM dealloc] + 148
9 libobjc.A.dylib 0x20a4 object_cxxDestructFromClass(objc_object*, objc_class*) + 116
10 libobjc.A.dylib 0x6e00 objc_destructInstance + 80
11 libobjc.A.dylib 0x104fc _objc_rootDealloc + 80
12 libobjc.A.dylib 0x20a4 object_cxxDestructFromClass(objc_object*, objc_class*) + 116
13 libobjc.A.dylib 0x6e00 objc_destructInstance + 80
14 libobjc.A.dylib 0x104fc _objc_rootDealloc + 80
15 UIKitCore 0x2008d8 -[UIResponder dealloc] + 124
16 UIKitCore 0x2005dc -[UIViewController dealloc] + 1084
17 libobjc.A.dylib 0x21d4 AutoreleasePoolPage::releaseUntil(objc_object**) + 196
18 libobjc.A.dylib 0x5bdc objc_autoreleasePoolPop + 256
19 UIKitCore 0x1a0444 -[_UIAfterCACommitBlock run] + 92
20 UIKitCore 0x1a0364 -[_UIAfterCACommitQueue flush] + 168
21 UIKitCore 0x1a0278 _runAfterCACommitDeferredBlocks + 496
22 UIKitCore 0x3eee4 _cleanUpAfterCAFlushAndRunDeferredBlocks + 108
23 UIKitCore 0x4fd608 _UIApplicationFlushCATransaction + 72
24 UIKitCore 0x64de00 _UIUpdateSequenceRun + 84
25 UIKitCore 0xcb1944 schedulerStepScheduledMainSection + 144
26 UIKitCore 0xcb0ea0 runloopSourceCallback + 92
27 CoreFoundation 0xd3208 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
28 CoreFoundation 0xdf864 __CFRunLoopDoSource0 + 176
29 CoreFoundation 0x646c8 __CFRunLoopDoSources0 + 244
30 CoreFoundation 0x7a1c4 __CFRunLoopRun + 828
31 CoreFoundation 0x7f4dc CFRunLoopRunSpecific + 612
32 GraphicsServices 0x135c GSEventRunModal + 164
33 UIKitCore 0x39d37c -[UIApplication _run] + 888
34 UIKitCore 0x39cfe0 UIApplicationMain + 340
35 SwiftUI 0x1bc3d8 OUTLINED_FUNCTION_895 + 2472
36 SwiftUI 0x1229b0 block_copy_helper.1 + 496
37 SwiftUI 0x10ca54 OUTLINED_FUNCTION_901 + 2752
38 AppName 0x7844 main + 23 (AppName.swift:23)
39 ??? 0x1ab1b0dec (Missing)
I don't get this crash when I am running in the simulator only when I run trough Firestore App distribution.
Code of the button causing crash and the viewModels:
@StateObject var viewModel: AuthViewModel.CreateAccountViewModel
...
Button("Create Account", action: viewModel.submit)
AuthViewModel:
func makeCreateAccountViewModel() -> CreateAccountViewModel {
return CreateAccountViewModel(action: authService.createAccount(name:email:password:))
}
class CreateAccountViewModel: FormViewModel<(name: String, email: String, password: String)> {
convenience init(action: @escaping Action) {
self.init(initialValue: (name: "", email: "", password: ""), action: action)
}
}
FormViewModel:
@MainActor
@dynamicMemberLookup
class FormViewModel<Value>: ObservableObject {
typealias Action = (Value) async throws -> Void
@Published var value: Value
@Published var error: Error?
@Published var isWorking = false
subscript<T>(dynamicMember keyPath: WritableKeyPath<Value, T>) -> T {
get { value[keyPath: keyPath] }
set { value[keyPath: keyPath] = newValue }
}
private let action: Action
init(initialValue: Value, action: @escaping Action) {
self.value = initialValue
self.action = action
}
nonisolated func submit() {
Task {
await handleSubmit()
}
}
private func handleSubmit() async {
isWorking = true
do {
try await action(value)
} catch {
print("[FormViewModel] Cannot submit: \(error)")
self.error = error
}
isWorking = false
}
}
AuthService:
private let auth = Auth.auth()
func createAccount(email: String, password: String) async throws {
let result = try await auth.createUser(withEmail: email, password: password)
try await result.user.updateProfile(\.displayName, to: email)
}
private extension FirebaseAuth.User {
func updateProfile<T>(_ keyPath: WritableKeyPath<UserProfileChangeRequest, T>, to newValue: T) async throws {
var profileChangeRequest = createProfileChangeRequest()
profileChangeRequest[keyPath: keyPath] = newValue
try await profileChangeRequest.commitChanges()
}
}
Please ask any questions and if there is anything that needs to be added to make it clearer.
Thanks
Further edits: After completing the suggestion from lorem ipsum I turned on "strict/complete concurrency" This gives me the following "error" on this code:
func createAccount(email: String, password: String) async throws {
let result = try await auth.createUser(withEmail: email, password: password)
try await result.user.updateProfile(\.displayName, to: email)
}
let result part: Non-sendable type 'AuthDataResult' returned by call from main actor-isolated context to non-isolated instance method 'createUser(withEmail:password:)' cannot cross actor boundary try await part: Non-sendable type 'WritableKeyPath<UserProfileChangeRequest, String?>' exiting main actor-isolated context in call to non-isolated instance method 'updateProfile(_:to:)' cannot cross actor boundary
Does anyone have advice on fixing this?
Thanks
Upvotes: 1
Views: 149
Reputation: 29291
The purpose of the MainActor wrapper is to keep UI updates on the main actor. You remove the safety by nonisolating and “leaking” the Task
.
Try something like
@State private var isProcessing: Bool = false
And
Button {
//This can start/stop a task
isProcessing.toggle()
} label: {
Text("Create Account")
.task(id: isProcessing) {
guard isProcessing else {
return
}
await viewModel.handleSubmit()
isProcessing = false
}
}
This will allow you to "hold on" to the task in the spirit of concurrency.
I would also suggest turning on "strict/complete concurrency" or at the very least "targeted".
Why does `Task<C, Error>` work even though `C` is a class which is not `Sendable`, or is it?
And add
-Xfrontend -warn-concurrency
-Xfrontend -enable-actor-data-race-checks
To Build Settings > Swift Compiler > Other Swift Flags
Upvotes: 0