iOS SwiftUI项目中@main入口触发Thread 1: EXC_BAD_ACCESS错误求助(点击注册按钮时触发)
Hey there, let's dig into this Thread 1: EXC_BAD_ACCESS error you're hitting when tapping the register button. I’ve spotted a critical issue that’s almost certainly causing this crash, plus a few other potential gotchas to fix up.
1. Critical Crash Cause: Duplicate AppDelegate Definitions
First off, your xxApp.swift file has three identical definitions of AppDelegate stacked on top of each other. This is a major problem—duplicate class definitions confuse the compiler and runtime, leading to invalid memory access (exactly the EXC_BAD_ACCESS error you’re seeing).
Fix: Clean Up Duplicate Code
Replace your entire xxApp.swift file with this corrected version (only one AppDelegate definition, plus fixed @main placement):
import SwiftUI import Firebase final class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { FirebaseApp.configure() return true } } @main struct PSMAApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate @StateObject var sessionService = SessionServiceImpl() var body: some Scene { WindowGroup { NavigationView{ switch sessionService.state { case .loggedIn: HomeView() .environmentObject(sessionService) case .loggedOut: LoginView() } } } } }
2. Potential Memory Leaks & Unmanaged Listeners
Even after fixing the duplicate class issue, there are two places where unmanaged listeners could cause future crashes or memory bloat:
Fix 1: Clean Up Firebase Auth & Database Listeners
Add a deinit method to your SessionServiceImpl to remove active listeners when the object is destroyed:
final class SessionServiceImpl: ObservableObject, SessionService { @Published var state: SessionState = .loggedOut @Published var userDetails: SessionUserDetails? private var handler: AuthStateDidChangeListenerHandle? private var databaseHandle: DatabaseHandle? // Add this init() { setupFirebaseAuthHandler() } func logout() { try? Auth.auth().signOut() } // Add this deinit method deinit { // Remove auth state listener if let authHandle = handler { Auth.auth().removeStateDidChangeListener(authHandle) } // Remove database value observer if let dbHandle = databaseHandle { Database.database().reference().child("users").removeObserver(withHandle: dbHandle) } } } private extension SessionServiceImpl { func setupFirebaseAuthHandler() { handler = Auth .auth() .addStateDidChangeListener { [weak self] res, user in guard let self = self else { return } self.state = user == nil ? .loggedOut : .loggedIn if let uid = user?.uid { self.handleRefresh(with: uid) } } } func handleRefresh(with uid: String) { // Store the database handle for cleanup later databaseHandle = Database .database() .reference() .child("users") .child(uid) .observe(.value) { [weak self] snapshot in guard let self = self, let value = snapshot.value as? NSDictionary, let username = value[RegistrationKeys.username.rawValue] as? String else{ return } DispatchQueue.main.async { self.userDetails = SessionUserDetails(username: username) } } } }
Fix 2: Improve Alert State Handling
Your current alert logic directly accesses vm.state inside the alert closure, which can lead to race conditions. Instead, add a dedicated published property for error messages in your RegistrationViewModelImpl:
final class RegistrationViewModelImpl: ObservableObject, RegistrationViewModel { @Published var hasError: Bool = false @Published var state: RegistrationState = .na @Published var errorMessage: String? // Add this let service: RegistrationService var userDetails: RegistrationDetails = RegistrationDetails.new private var subscriptions = Set<AnyCancellable>() init(service: RegistrationService) { self.service = service setupErrorSubscriptions() } // ... existing register() method ... } private extension RegistrationViewModelImpl { func setupErrorSubscriptions() { $state .map { state -> (Bool, String?) in switch state { case .successfull, .na: return (false, nil) case .failed(let error): return (true, error.localizedDescription) } } .sink { [weak self] hasError, message in self?.hasError = hasError self?.errorMessage = message } .store(in: &subscriptions) } }
Then update your RegisterView alert to use this safer property:
.alert(isPresented: $vm.hasError, content: { Alert( title: Text("Error"), message: Text(vm.errorMessage ?? "Something went wrong") ) })
Final Steps to Ensure Fix
- Clean your project build folder (press
Cmd+Shift+Kin Xcode) to clear any cached artifacts from the duplicate class definition. - Rebuild and run your app—this should resolve the EXC_BAD_ACCESS crash immediately.
- Double-check that your
GoogleService-Info.plistis properly added to your project and assigned to the correct target.
内容的提问来源于stack exchange,提问作者Loco2343

