You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xcode 14中自定义URL Scheme数据从AppDelegate传至ViewController为空,原因何在?

问题原因&解决方案

为什么数据为空?

核心是代码执行时序不匹配:

  1. 首次通过URL Scheme启动App时,ViewController的viewDidLoad会先执行,之后才会调用AppDelegate里的application(_:open:url:options:)方法。你在viewDidLoad里读取mytr时,它还没被赋值,自然是空字符串。
  2. 如果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,提问作者鄭小火

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 01:31:23