使用异步时如何在主线程上进行调用?我们如何/为什么离开主线程?

Cha*_*nce 5 uikit async-await swift

晚安,抱歉我的英语不好,我正在学习 swift async/await、任务和调度。好吧,我得到了执行谷歌登录的代码块有几个回调,所以我尝试将整个方法转换为异步。

self.navigationController?.dismiss(animated: true, completion: nil)我的问题是,当我调用重构方法并应用 async/await 时,我在使用断点执行时收到错误Thread 14: "Call must be made on main thread"

我明白他的意思,但是如何在主线程上运行 .dimiss ?我说我已经不在主线了?它是从什么时候出来的,我不太明白。

这是我的带有链式回调的代码,它工作正常。

    guard let clientId = FirebaseApp.app()?.options.clientID else {
        print("failed get clientId google signin")
        return
    }
    
    let config = GIDConfiguration(clientID: clientId)
    
    GIDSignIn.sharedInstance.signIn(with: config, presenting: self, callback: { [weak self] authResult, error in
                guard let strongSelf = self else {
                    return
                }

                guard authResult != nil, error == nil else {
                    if let error = error {
                        print("failed login with google sign in \(error)")
                    }
                    return
                }


                guard let authentication = authResult?.authentication,
                      let idToken = authentication.idToken else {
                          return
                      }
                guard let email = authResult?.profile?.email,
                      let firstName = authResult?.profile?.givenName,
                      let lastName = authResult?.profile?.familyName else {
                          return;
                      }

                DatabaseManager.shared.userExists(with: email, completion: { exists in
                    if !exists {
                        //insert database
                        let chatUser = ChatAppUser(firtName: firstName, lastName: lastName, emailAddress: email)
                        DatabaseManager.shared.insertUser(with: chatUser, completion: { success in
                            if success {
                                //upload image
                                if ((authResult?.profile?.hasImage) != nil) {
                                    guard let url = authResult?.profile?.imageURL(withDimension: 200) else {
                                        return
                                    }

                                    URLSession.shared.dataTask(with: url, completionHandler: {data, _, _ in
                                        guard let data = data else {
                                            return
                                        }
                                        let fileName = chatUser.profilePictureFileName
                                        StorageManager.shared.uploadProfilePicture(with: data, fileName: fileName, completion: { result in
                                            switch result {
                                            case .success (let downloadUrl):
                                                UserDefaults.standard.set(downloadUrl, forKey: "profile_picture_url")
                                                print(downloadUrl)
                                            case .failure(let error):
                                                print("Storage manager error: \(error)")
                                            }
                                        })
                                    }).resume()


                                }

                            }
                        })
                    }
                })
                let credentials = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: authentication.accessToken)

                Auth.auth().signIn(with: credentials, completion: {authResult, error in
                    guard authResult != nil, error == nil else {
                        if let error = error {
                            print("google credential login failed, MFA may be needed \(error)")
                        }
                        return;
                    }

                    print("successFully logged user in")

                    strongSelf.navigationController?.dismiss(animated: true, completion: nil)
                })
            })
Run Code Online (Sandbox Code Playgroud)

这是我应用了 async/await 的代码。

    guard let clientId = FirebaseApp.app()?.options.clientID else {
        print("failed get clientId google signin")
        return
    }
    
    let config = GIDConfiguration(clientID: clientId)
   
    do {
        let resultSignin = try await GoogleManager.shared.googleSignin(config: config, presenting: self)
        switch resultSignin {
        case .success(let autheResult):
            let authentication = autheResult.authentication
            guard let idToken = authentication.idToken else {
                break
            }
            
            //function authentication
            guard let email = autheResult.profile?.email,
                  let firstName = autheResult.profile?.givenName,
                  let lastName = autheResult.profile?.familyName else {
                      break
                  }
            let ifExist = try await DatabaseManager.shared.userExists(with: email)
            if ifExist {
                let chatUser = ChatAppUser(firtName: firstName, lastName: lastName, emailAddress: email)
                let resultInsert = try await DatabaseManager.shared.insertUser(with: chatUser)
                if resultInsert {
                    if autheResult.profile?.hasImage != nil {
                        guard let url = autheResult.profile?.imageURL(withDimension: 200) else{
                            break
                        }
                        
                        let dataPicture = await ApiManager.shared.getData(url: url)
                        
                        guard let dataPicture = dataPicture else {
                            break
                        }
                        let fileName = chatUser.profilePictureFileName
                        let resultUpload = try await StorageManager.shared.uploadProfilePicture(with: dataPicture, fileName: fileName)
                        switch resultUpload {
                        case .success (let downloadUrl):
                            UserDefaults.standard.set(downloadUrl, forKey: "profile_picture_url")
                            print(downloadUrl)
                            break
                        case .failure(let error):
                            print("Storage manager error: \(error)")
                            alertUserLoginError(message: "Storage manager error: \(error)")
                            break
                        }
                        
                    }
                }
            }
            
            let credentials = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: authentication.accessToken)
            let authResult = try await Auth.auth().signIn(with: credentials)
            print("Logged In user: \(authResult.user)")
            self.navigationController?.dismiss(animated: true, completion: nil)
            break
        case .failure(let error):
            alertUserLoginError(message: "Error: \(error)")
            break
            
        }
        
    }catch let error as NSError {
        print("Try catch error: \(error)")
        alertUserLoginError(message: "Try catch error: \(error)")
    }
Run Code Online (Sandbox Code Playgroud)

谷歌登录

final class GoogleManager {
    static let shared = GoogleManager()
    
    private let googleInstance = GIDSignIn.sharedInstance

}


extension GoogleManager {
    
    public func googleSignin(config: GIDConfiguration, presenting: UIViewController, completion: @escaping (Result<GIDGoogleUser,Error>) -> Void){
        googleInstance.signIn(with: config, presenting: presenting, callback: { authResult, error in
            guard authResult != nil, error == nil else {
                completion(.failure(error!))
                return
            }
            
            completion(.success(authResult!))
        })
    }
    
    public func googleSignin(config: GIDConfiguration, presenting: UIViewController) async throws -> (Result<GIDGoogleUser, Error>) {
        await withCheckedContinuation { continuation in
            googleSignin(config: config, presenting: presenting, completion: { result in
                continuation.resume(returning: result)
            })
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

堆栈跟踪:

Main Thread Checker: UI API called on a background thread: -[UIViewController navigationController]
PID: 426, TID: 18401, Thread name: (none), Queue name: Swift global concurrent queue, QoS: 25
Backtrace:
4   Messenger                           0x0000000102dc0360 $s9Messenger19LoginViewControllerC19googleButtonClicked022_498C1017229A4D9B461B7L9B38EF23C9LLyyYaFTQ5_
Run Code Online (Sandbox Code Playgroud)