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

Swift中无法从其他ViewController获取值的问题求助

解决设置页面数据回传及初始值读取问题

看起来你遇到的核心问题有两个:一是首次启动App时,未访问过设置页面就无法获取到设置值,二是设置变更后无法实时同步到上一个ViewController。我们来一步步解决这些问题:

1. 先解决初始值缺失的问题

你的代码里没有给UserDefaults的engS键设置默认值,所以第一次打开App时,defaults.value(forKey: engS)会返回nil,导致上一个VC读取不到有效数据。我们可以在设置页面加载时,先检查并设置默认值:

class SetConvViewController: UIViewController {
    let engS = "engS"
    @IBOutlet weak var swithEnglish: UISwitch!
    let defaults = UserDefaults.standard

    override func viewDidLoad() {
        super.viewDidLoad()
        // 检查是否存在初始值,不存在则设置默认状态(这里默认关闭,你可以改成true)
        if !defaults.bool(forKey: engS) {
            defaults.set(false, forKey: engS)
        }
        // 用bool(forKey:)更安全,避免强制解包
        swithEnglish.isOn = defaults.bool(forKey: engS)
    }

    @IBAction func switchEng(_ sender: UISwitch) {
        defaults.set(sender.isOn, forKey: engS)
    }
}

这样即使用户从未打开过设置页面,UserDefaults里也会有engS的默认值,上一个VC随时可以读取。

2. 实时同步设置到上一个ViewController

接下来解决数据回传的问题,这里推荐两种实用方案:

方案一:闭包回调(最直接的页面间传值方式)

在设置页面定义一个闭包属性,当开关状态变化时,调用闭包把新值传递给上一个VC:

class SetConvViewController: UIViewController {
    let engS = "engS"
    @IBOutlet weak var swithEnglish: UISwitch!
    // 定义回调闭包,用于通知上一个VC设置变更
    var onSettingUpdated: ((Bool) -> Void)?
    let defaults = UserDefaults.standard

    override func viewDidLoad() {
        super.viewDidLoad()
        if !defaults.bool(forKey: engS) {
            defaults.set(false, forKey: engS)
        }
        swithEnglish.isOn = defaults.bool(forKey: engS)
    }

    @IBAction func switchEng(_ sender: UISwitch) {
        defaults.set(sender.isOn, forKey: engS)
        // 开关变化时立即通知上一个VC
        onSettingUpdated?(sender.isOn)
    }

    // 也可以在用户返回时再传递一次(防止用户直接按返回键没触发开关事件)
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if isMovingFromParent {
            onSettingUpdated?(defaults.bool(forKey: engS))
        }
    }
}

然后在上一个VC中,跳转到设置页面时绑定这个闭包:

// 假设上一个VC是MainViewController
class MainViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // 页面加载时先读取当前设置值
        let currentSetting = UserDefaults.standard.bool(forKey: "engS")
        updateUI(with: currentSetting)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let setVC = segue.destination as? SetConvViewController {
            // 绑定回调闭包,接收设置变更
            setVC.onSettingUpdated = { [weak self] isEnglishOn in
                self?.updateUI(with: isEnglishOn)
            }
        }
    }

    // 根据设置更新UI的方法
    func updateUI(with isEnglishOn: Bool) {
        // 这里写你的UI更新逻辑,比如切换语言显示、调整布局等
        print("当前英文开关状态:\(isEnglishOn)")
    }
}

方案二:监听UserDefaults通知(全局同步变更)

如果你的App有多个页面需要同步这个设置,推荐用NotificationCenter监听UserDefaults的变化,这样任何地方修改了设置,所有监听的页面都会收到通知:

在上一个VC中添加监听:

class MainViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // 注册UserDefaults变更通知
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(onSettingChanged),
            name: UserDefaults.didChangeNotification,
            object: nil
        )
        // 初始化UI
        let currentSetting = UserDefaults.standard.bool(forKey: "engS")
        updateUI(with: currentSetting)
    }

    @objc func onSettingChanged() {
        // 收到通知后读取最新设置并更新UI
        let currentSetting = UserDefaults.standard.bool(forKey: "engS")
        updateUI(with: currentSetting)
    }

    func updateUI(with isEnglishOn: Bool) {
        // 你的UI更新逻辑
        print("当前英文开关状态:\(isEnglishOn)")
    }

    // 记得在页面销毁时移除监听
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

这种方式不需要修改设置页面的回调逻辑,只要设置页面修改了UserDefaults,所有监听的页面都会自动同步。

为什么之前的方法无效?

你之前的问题主要是:

  • 没有给UserDefaults设置初始值,导致未访问设置页面时无值可读;
  • 没有建立实时的通知/回调机制,上一个VC无法感知设置页面的变更,只有再次进入设置页面时才会读取值。

按照上面的方案修改后,就能解决这两个问题啦!

内容的提问来源于stack exchange,提问作者Jacob

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:36:00