【问题标题】:App Crashing with EXC_BREAKPOINT Error应用程序因 EXC_BREAKPOINT 错误而崩溃
【发布时间】:2015-11-22 15:33:32
【问题描述】:

我有一个正在 Xcode 7.2 中制作的应用程序。我有一个带有一个按钮的主菜单,该按钮有一个转到设置视图控制器的 segue。设置视图控制器具有以下代码,每次我到达该视图控制器时,它都会因 EXC_BREAKPOINT 错误而崩溃。有趣的是,这只发生在我运行 iOS 7 的 iPhone 4 上。它不会在运行 iOS 9 的 iOS 模拟器 iPhone 6 中崩溃。

不管怎样,这里是代码。

//
//  SettingsController.swift
//  Arbor Hills iOS
//
//  Created by Andrew on 11/22/15.
//  Copyright © 2015 Arbor Hills Vet. All rights reserved.
//

import UIKit

class SettingsController: UITableViewController {

    @IBOutlet weak var username: UITextField!
    @IBOutlet weak var password: UITextField!
    @IBOutlet weak var notifications: UISwitch!
    override func viewDidLoad(){
        super.viewDidLoad()

        let defaults = NSUserDefaults.standardUserDefaults()
        let dusername = defaults.valueForKey("username")!

        let dpassword = defaults.valueForKey("password")!
        let dnotifications = defaults.valueForKey("notifications")!

        username!.text = String(dusername)
        password!.text = String(dpassword)
        if(dnotifications as! Bool == true){
            notifications.setOn(true, animated: true)
        }else{
            notifications.setOn(false, animated:true)
        }
    }

    @IBAction func saveUsername(sender: AnyObject) {
       let defaults = NSUserDefaults.standardUserDefaults()
        defaults.setObject(username.text!, forKey: "username")
    }

    @IBAction func savePassword(sender: AnyObject) {
        let defaults = NSUserDefaults.standardUserDefaults()
        defaults.setObject(password.text!, forKey: "password")
    }

    @IBAction func notificationsModified(sender: AnyObject) {
        let defaults = NSUserDefaults.standardUserDefaults()
        defaults.setObject(notifications.on, forKey: "notifications")
    }

    }

【问题讨论】:

  • 在 viewDidLoad 中设置断点,从 iphone4s ios 7 开始在此中逐行调试,让我们知道它在哪里崩溃。
  • @RajanMaheshwari 在这一行之后崩溃了:let dusername = defaults.valueForKey("username")!
  • 表示用户名密钥数据不存在。在那里进行零检查

标签: ios iphone xcode swift


【解决方案1】:

NSUserDefaults 如果没有注册默认值,则为对象返回nil。当您解开 nil 值时,您将收到运行时错误(崩溃)。

Apple 建议为任何键注册一个默认值作为占位符,直到第一次保存自定义值。

AppDelegate 中添加applicationDidFinshLaunching

let defaults = NSUserDefaults.standardUserDefaults()
let defaultValues = ["username" : "", "password" : "", "notifications" : false]
defaults.registerDefaults(defaultValues)

Swift 3+

let defaults = UserDefaults.standard
let defaultValues : [String : Any] = ["username" : "", "password" : "", "notifications" : false]
userDefaults.register(defaults: defaultValues)

注册空字符串和布尔值false
然后您就可以安全地检索这些值了

let defaults = NSUserDefaults.standardUserDefaults()
let dusername = defaults.stringForKey("username")!
let dpassword = defaults.stringForKey("password")!
let dnotifications = defaults.boolForKey("notifications")

Swift 3+

let defaults = UserDefaults.standard
let dusername = defaults.string(forKey:"username")!
let dpassword = defaults.string(forKey:"password")!
let dnotifications = defaults.bool(forKey:"notifications")

对于String 值始终使用stringForKey,对于Bool 值使用boolForKey
从不valueForKeyNSUserDefaults 一起使用,这是一种特殊的KVC 方法。

那么这段代码也可以简化:

username!.text = dusername
password!.text = dpassword
notifications.setOn(dnotifications, animated: true)

当写入用户默认值时,使用setBool:forKey 作为Bool 值,但是没有等效的StringsetObject:forKey 是正确的。

【讨论】:

  • 谢谢。这有很大帮助。我想我不知道 registerDefaults 方法。
  • 不幸的是,尽管文档中有详细描述并且自 Mac OS 10.0 起可用,但大多数人都不知道注册默认值
  • 我现在看到您修复了 OP 对 valueForKey 的滥用以及注册“默认默认值”值。 (投票)。我唯一会改变你的代码的想法不是强制解包可选,而是使用if let。在这种情况下,由于注册了默认值,它会起作用,但使用用户默认值不是一个好习惯,因为如果默认值不存在,它将崩溃。
  • 注册默认值的主要目的是让您始终拥有 100% 安全的非可选值。根本不需要可选绑定。当您第一次启动应用程序时,您有 2 个字符串和一个布尔值,它们永远不会为零。
  • 注册默认值很有帮助。我总是在应用程序委托的 initialize() 调用中调用registerDefaultValues,该调用甚至在应用程序委托被实例化之前就被调用了。这样您就可以放心地假设您的“默认默认”值是在您的应用程序代码的 **ALL(() 中定义的。
【解决方案2】:

你不应该使用 valueForKey 从 NSUserDefaults 中获取对象。那是一种键值编码方法。 (见NSKeyValueCoding上的链接。你想要objectForKey,你需要检查nil afterwords:

let defaults = NSUserDefaults.standardUserDefaults()
if let dusername = defaults.objectForKey("username") as String
{
  //code to use the username
}
else
{
  //code to handle the case where there is no username
}

【讨论】:

  • 不,他应该使用stringForKey,而不是objectForKey。看我的回答;-)
  • 两者都是有效的,是的,我同意使用 stringForKey 更干净。我的观点是问题中的代码无法正常工作。
  • 我知道,我几乎从字面上引用您的评论是在开玩笑。尽管如此,推荐使用注册默认值。
  • @vadian 寄存器值我猜和初始化键值一样。
  • @vadian 还有 registerDefaults 仅在键 val 为 nil 或每次为相应键设置默认值时运行?
猜你喜欢
  • 2019-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-07
  • 2014-04-02
相关资源
最近更新 更多