【问题标题】:unexpectedly found nil while unwrapping an Optional value keyboardWillShow展开可选值keyboardWillShow时意外发现nil
【发布时间】:2017-01-23 23:51:40
【问题描述】:

下面的代码在调用 keyboardWillShowNotification 时运行:

func keyboardWillShow(_ notification: Notification) {
    //ERROR IN THE LINE BELOW            
    keyboard = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as AnyObject).cgRectValue
    animaton = (notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as AnyObject).doubleValue

    UIView.animate(withDuration: 0.4, animations: { () -> Void in
       self.scrollView.frame.size.height = self.scrollViewHeight - self.keyboard.height
    }) 
}

我在第二行收到错误消息:unexpectedly found nil while unwrapping an Optional value。基本上,每当我单击其中一个文本字段时,都会调用此键盘通知,并且keyboardWillShow 中的代码将运行。我知道我放了if...let 声明,但我想知道为什么我会为此得到零。

我不确定我是如何得到这个错误的,或者如何调试它。是不是因为我是在模拟器上运行的?

这是打印 notification.userInfo 给出的内容:

可选([AnyHashable("UIKeyboardFrameEndUserInfoKey"): NSRect: {{0, 315}, {320, 253}}, AnyHashable("UIKeyboardIsLocalUserInfoKey"): 1, AnyHashable("UIKeyboardBoundsUserInfoKey"): NSRect: {{0 , 0}, {320, 253}}, AnyHashable("UIKeyboardAnimationCurveUserInfoKey"): 7, AnyHashable("UIKeyboardCenterBeginUserInfoKey"): NSPoint: {160, 694.5}, AnyHashable("UIKeyboardCenterEndUserInfoKey"): NSPoint: {160, 441.5}, AnyHashable("UIKeyboardFrameBeginUserInfoKey"): NSRect: {{0, 568}, {320, 253}}, AnyHashable("UIKeyboardAnimationDurationUserInfoKey"): 0.25])

【问题讨论】:

  • 记录notification.userInfo。查看实际存在哪些键。
  • 哦,让我试试。
  • 我在我的问题中添加了打印出来的内容。显示UIKeyboardFrameEndUserInfoKey可用。
  • 当我注释掉这两行时:keyboard = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as AnyObject).cgRectValueanimaton = (notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as AnyObject).doubleValue 键盘会正确弹出,也不会出现 nil 错误。
  • 只需将其转换为 NSValue 而不是 AnyObject

标签: ios swift swift3 uikeyboard nsnotification


【解决方案1】:

(Leo Dabus 的回答中清楚地写了如何解决您的问题,所以我会尝试解释我在添加之前遇到的错误!。)

在 Swift 3 中,as AnyObject 已成为风险最大的操作之一。 它与称为id-as-Any 的最糟糕的新功能有关。

在这行代码中:

    keyboard = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as AnyObject).cgRectValue

表达式notification.userInfo?[UIKeyboardFrameEndUserInfoKey] 的类型是Any?。如您所见,不应将 Optional 类型 Any? 安全地转换为非 Optional AnyObject。但是 Swift 3 通过创建非可选 _SwiftValue 来转换它。

您可以通过插入此代码来检查此行为:

print(type(of: notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as AnyObject))

因此,您正在尝试将非可选链接 .cgRectValue 应用于 _SwiftValue,这可能会混淆 Swift 3 的功能:“隐式类型转换 _SwiftValue 回 Swift 值”。

太长了……


不要在 Swift 3 中使用 as AnyObject 强制转换

【讨论】:

  • 您好,很抱歉回复晚了,感谢您的详细解答!我有一个问题:您在这里说:“如您所见,不应将可选类型 Any? 安全地转换为非可选 AnyObject。但是 Swift 3 通过创建非可选 _SwiftValue 将其转换为”我不不了解这部分:swift 3 将其转换为非可选的_SwiftValue。你的意思是notification.userInfo?[UIKeyboardFrameEndUserInfoKey] 的值Any? 被转换为非可选类型_SwiftValue?还有_SwiftValue在这里指的是什么?
  • @1290, 你的意思是notification.userInfo?[UIKeyboardFrameEndUserInfoKey]的值Any?被转换为非可选类型_SwiftValue? 绝对是的. _SwiftValue 在这里指的是什么? 这是一个隐藏的类型,还没有透露太多, - 它是一个引用类型。 - 它可以包含 Swift 的任何值。 - Swift 运行时知道如何检索其中包含的原始值,并且在某些情况下,会自动将其转换为 Swift 类型。
  • 哦,我现在明白了!非常感谢您的清晰解释帮助很大。
【解决方案2】:

来自文档:

let UIKeyboardFrameEndUserInfoKey: String 

说明

包含标识 CGRect 的 NSValue 对象的键 屏幕坐标中键盘的结束帧

你的第二把钥匙:

let UIKeyboardAnimationDurationUserInfoKey: String

描述 NSNumber 对象的键包含一个双精度 以秒为单位标识动画的持续时间。

所以你需要将第一个转换为 NSValue,第二个转换为 NSNumber:

func keyboardWillShow(_ notification: Notification) {
    print("keyboardWillShow")
    guard let userInfo = notification.userInfo else { return }
    keyboard = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
    animaton = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
    // your code
}

【讨论】:

  • 您好!将UIKeyboardFrameEndUserInfoKey 键的值存储在NSValue 中的目的是什么?为什么不将其存储在 CGRect 本身中?我在网上看到NSValue 是一个简单的容器,用于存放单个 C 或 Objective-C 数据项。 CGRect 也是一个 Objective-C 数据项,这就是我们将其包装在 NSValue 中的原因?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-18
  • 2017-04-09
  • 2018-09-22
  • 2016-06-26
  • 2016-03-12
  • 2021-12-30
相关资源
最近更新 更多