2016-09-15 77 views
2

我有这样的代码低于当keyboardWillShowNotification被称为运行:unexpectedly found nil while unwrapping an Optional value意外地发现零而展开的可选值keyboardWillShow

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 
    }) 
} 

我在第二行说得到一个错误。基本上每当我点击其中一个textField时,这个键盘通知就会被调用,并且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])

+0

登录'notification.userInfo'不要使用as AnyObject铸造。查看实际存在的密钥。 – rmaddy

+0

噢,让我试试。 – CapturedTree

+0

我在问题中添加了什么打印出来。它显示'UIKeyboardFrameEndUserInfoKey'可用。 – CapturedTree

回答

3

从文档:

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 
} 
+0

您好!将“UIKeyboardFrameEndUserInfoKey”键的值存储在“NSValue”中的目的是什么?为什么不把它存储在CGRect本身?我在网上阅读,“NSValue”是一个单一的C或Objective-C数据项的简单容器。那么'CGRect'是一个Objective-C数据项,这就是为什么我们要将它包装在一个'NSValue'中? – CapturedTree

2

(如何解决您的问题写清楚在狮子Dabus的答案,所以我会尽量解释我在添加之前得到的错误!。)

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

在这一行代码的:

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

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

您可以将这段代码检查这种行为:

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

所以,你想申请非可选链式.cgRectValue_SwiftValue,这可能会产生混淆的斯威夫特3的功能:“隐式类型转换_SwiftValue回到Swift值“。

获取太长......


斯威夫特3

+0

你好,很抱歉迟到的答复,谢谢你的详细解答!我有一个问题:你在这里陈述道:“正如你看到的,一个可选类型'Any?'不应该安全地转换为非可选'AnyObject',但Swift 3通过创建非可选'_SwiftValue'来转换它”不理解这部分:swift 3将它转换为非可选的'_SwiftValue'。你的意思是说''notification.userInfo?[UIKeyboardFrameEndUserInfoKey]'是'Any?'的值是否被转换为非可选类型'_SwiftValue'?此外'_SwiftValue'指的是什么? – CapturedTree

+1

@ 1290,_你的意思是说,任何?'notification.userInfo?[UIKeyboardFrameEndUserInfoKey]的值被转换为非可选类型'_SwiftValue'?绝对是的。 _SwiftValue在这里指的是什么_这是一个隐藏类型,目前还没有透露 - 它是一个引用类型。 - 它可以包含任何Swift的值。 - Swift运行时知道如何检索包含在其中的原始值,并且可能会自动将其转换为Swift类型。 – OOPer

+0

哦,我现在看到了!非常感谢你的明确解释帮助了很多。 – CapturedTree

相关问题