设置webAuthSession.presentationContextProvider = self时提示“找不到self”的问题求助
解决Web认证中"Cannot find 'self' in scope"错误
问题根源
你遇到的错误核心原因是:
webAuthSession实例和TeslaSignIn函数都定义在全局作用域,而非实现了ASWebAuthenticationPresentationContextProviding协议的SignInViewModel类内部,此时self没有对应的类实例上下文- 协议实现与认证会话逻辑完全分离,导致无法关联上下文提供者
修正后的完整代码
import Foundation import AuthenticationServices import CryptoKit import UIKit typealias ASPresentationAnchor = UIWindow class SignInViewModel: NSObject, ObservableObject, ASWebAuthenticationPresentationContextProviding { // 将认证会话作为类属性,延迟初始化 private var webAuthSession: ASWebAuthenticationSession? // 实现协议方法,返回当前应用的主窗口(修正原代码直接创建空窗口的问题) func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { return UIApplication.shared.windows.first ?? ASPresentationAnchor() } // 生成认证URL的方法移到类内部,改为静态方法 private static func generateAuthURL() -> URL { func randomString(length: Int) -> String { let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" return String((0..<length).map{ _ in letters.randomElement()! }) } let codeVerifier = randomString(length: 86) let hashData = Data(codeVerifier.utf8) let codeChallengeData = SHA256.hash(data: hashData) let codeChallenge = codeChallengeData.compactMap { String(format: "%02x", $0) }.joined() let baseURL = "https://auth.tesla.com/oauth2/v3/authorize" let parameters = [ "client_id": "ownerapi", "code_challenge": codeChallenge, "code_challenge_method": "S256", "redirect_uri": "https://auth.tesla.com/void/callback", "response_type": "code", "scope": "openid+email+offline_access", "state": codeVerifier ] // 用URLComponents构建URL,避免字符串拼接的编码问题 var components = URLComponents(string: baseURL)! components.queryItems = parameters.map { URLQueryItem(name: $0.key, value: $0.value) } return components.url! } // 登录方法改为类实例方法 func teslaSignIn() { guard webAuthSession == nil else { return } webAuthSession = ASWebAuthenticationSession( url: Self.generateAuthURL(), callbackURLScheme: "TESRIUM", completionHandler: { [weak self] callbackURL, error in // 处理认证回调逻辑 if let error = error { print("认证错误:\(error.localizedDescription)") } else if let callbackURL = callbackURL { print("回调URL:\(callbackURL)") // 解析code等参数 } // 重置会话 self?.webAuthSession = nil } ) webAuthSession?.presentationContextProvider = self webAuthSession?.prefersEphemeralWebBrowserSession = false webAuthSession?.start() } }
关键修改说明
- 作用域调整:将所有认证相关逻辑移到
SignInViewModel类内部,确保self指向实现了协议的类实例 - 会话管理:用
private var webAuthSession: ASWebAuthenticationSession?存储会话实例,避免全局变量导致的生命周期问题 - URL构建优化:改用
URLComponents生成认证URL,解决字符串拼接可能带来的编码错误 - 窗口获取修正:
presentationAnchor返回当前应用的主窗口,而非创建新窗口,符合ASWebAuthenticationSession的要求 - 内存安全:在completionHandler中使用
[weak self]避免循环引用
内容的提问来源于stack exchange,提问作者BlazeProg
相关产品推荐
相关产品推荐

