Xcode 14中自定义URL Scheme数据从AppDelegate传至ViewController为空,原因何在?
问题原因&解决方案
为什么数据为空?
核心是代码执行时序不匹配:
- 首次通过URL Scheme启动App时,
ViewController的viewDidLoad会先执行,之后才会调用AppDelegate里的application(_:open:url:options:)方法。你在viewDidLoad里读取mytr时,它还没被赋值,自然是空字符串。 - 如果App已经在后台运行,通过URL Scheme唤醒时,
application(_:open:url:options:)会执行,但ViewController的viewDidLoad不会再次触发,所以也拿不到更新后的数据。
解决方案
方案1:用通知中心传递数据(适配所有场景)
通过通知机制,在AppDelegate拿到数据后主动通知ViewController,不管是首次启动还是后台唤醒都能生效。
修改AppDelegate代码:
var window: UIWindow? func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { let mytr = "TheData" // 这里可以替换为从URL解析的实际参数 // 发送通知传递数据 NotificationCenter.default.post(name: NSNotification.Name("URLSchemeDataReceived"), object: mytr) return true }
修改ViewController代码:
override func viewDidLoad() { super.viewDidLoad() self.webView.uiDelegate = self // 监听通知 NotificationCenter.default.addObserver(self, selector: #selector(handleReceivedData(_:)), name: NSNotification.Name("URLSchemeDataReceived"), object: nil) // 兼容App已启动的情况:直接检查AppDelegate里的缓存数据 if let appDelegate = UIApplication.shared.delegate as? AppDelegate, let data = appDelegate.mytr { useData(data) } } // 处理收到的数据 @objc func handleReceivedData(_ notification: Notification) { guard let data = notification.object as? String else { return } useData(data) // 可选:把数据缓存到AppDelegate,方便其他地方读取 let appDelegate = UIApplication.shared.delegate as? AppDelegate appDelegate?.mytr = data } // 这里写你处理数据的业务逻辑 func useData(_ data: String) { print("拿到的URL Scheme数据:\(data)") // 比如更新webView内容、刷新UI等 } // 记得移除监听,避免内存泄漏 deinit { NotificationCenter.default.removeObserver(self) }
方案2:启动时直接传值给ViewController(仅适配首次启动)
如果只需要处理首次通过URL Scheme启动的场景,可以在App启动阶段就把数据传递给ViewController。
修改AppDelegate代码:
var window: UIWindow? var mytr: String? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 检查是否通过URL Scheme启动 if let url = launchOptions?[.url] as? URL { mytr = "TheData" // 替换为实际解析的URL参数 // 把数据传给根ViewController if let rootVC = window?.rootViewController as? ViewController { rootVC.receivedURLData = mytr } } return true } func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { mytr = "TheData" // 后台唤醒时,直接通知ViewController更新数据 if let rootVC = window?.rootViewController as? ViewController { rootVC.receivedURLData = mytr rootVC.useData(mytr!) } return true }
修改ViewController代码:
var receivedURLData: String? override func viewDidLoad() { super.viewDidLoad() self.webView.uiDelegate = self // 处理启动时传递的数据 if let data = receivedURLData { useData(data) } } func useData(_ data: String) { // 业务逻辑处理 print("拿到的数据:\(data)") }
额外提示
- 不要用
String!强制解包,建议改成可选类型String?,避免空值导致崩溃。 - 如果需要从URL里解析实际参数,可以用
url.queryItems来提取键值对,比如:let queryItems = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems let targetValue = queryItems?.first(where: { $0.name == "key" })?.value
内容的提问来源于stack exchange,提问作者鄭小火
相关产品推荐
相关产品推荐

