IOS Swift 致命错误如何展开可选值
IOS Swift How can fatal error unwrapping optional value
我有一个名为 BookViewC 的 ViewController,它所做的只是显示 1 个视频。故事板包含一个名为 FullName 的 IBOutlet 和一个我用来显示视频的 UIView。我有一个功能,当你点击视频时,它应该会得到下一个视频。 当我获取下一个视频时,我总是得到 FullName 的 nil 值,它总是正确地获取第一个视频。
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an
Optional value
在 fullname 的 IBOutLet 上,我明白为什么,有没有办法解决这个问题?这是我用来清理问题的代码
class BookViewC: UIViewController, VideoViewDelegate{
@IBOutlet weak var VideoView: UIView!
@IBOutlet weak var FullName: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// This method queries the database for the latest video
ReloadTable(Offset: 0)
}
func reloadTable(Offset: Int) {
// Queries the database for video name
// Returns data in Json
DispatchQueue.main.async {
for Stream in Streams! {
if let fullname = Stream["fullname"] as? String {
// This below throws the nil error when getting the 2nd video
self.FullName.setTitle(fullname, for: .normal)
}
}
// Method below simply shows the video
self.PlayVideo(MediaHeight: Float(pic_height), MediaURL: s_image)
}
func PlayVideo(MediaHeight: Float, MediaURL: String) {
let movieURL = URL(string: MediaURL)
videoCapHeight.constant = CGFloat(MediaHeight)
streamsModel.playerView = AVPlayer(url: movieURL!)
streamsModel.MyAVPlayer.player = streamsModel.playerView
streamsModel.MyAVPlayer.videoGravity = AVLayerVideoGravity.resizeAspectFill.rawValue
streamsModel.MyAVPlayer.showsPlaybackControls = false
streamsModel.MyAVPlayer.view.frame = VideoView.bounds
VideoView.addSubview(streamsModel.MyAVPlayer.view)
self.addChildViewController(streamsModel.MyAVPlayer)
streamsModel.playerView?.isMuted = false
streamsModel.MyAVPlayer.player?.play()
}
}
当您点击视频时,它会转到此 class
class CustomAVPLayerC: AVPlayerViewController {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// I try to return to my original Class now
let BookC = BookViewC()
for touch in touches {
let location = touch.location(in: self.view)
if location.x < self.view.layer.frame.size.width / 2 {
print("Tapped Left")
}
else {
print("Tapped Right get next video")
// Offset is now 1 which gets the 2nd video
BookC.ReloadTable(offset: 1)
}
}
}
}
发生的事情是,一旦我转到 CustomAVPLayerC 控制器,BookViewC 中的所有 IBOutlet 都变为 nil,然后一旦我尝试返回,它就会给我错误。我能做些什么来解决这个问题或解决它吗?我显示的视频使用 AVPlayer 所以点击我必须去 CustomAVPLayerC Controller 。任何建议都会很棒。
这些行可能导致您的问题:
// I try to return to my original Class now
let BookC = BookViewC()
这是创建 BookViewC class 的 新 副本,而不是让您回到原来的状态。然后当您告诉它 reloadTable
它没有任何可以使用的视图。
解决此问题的方法是确保您当前的 BookViewC 对象(第一段代码中的 this
)可供视频播放器调用 reloadTable
方法。执行此操作的正常方法是通过 delegate
模式。
IBOutlets
为零,因为您的 BookVC
未从 .xib/storyboard
初始化。使用委托模式应该可以解决问题。以下是一个可以帮助实现这一目标的示例,
创建如下协议,
protocol CustomAVPLayerProtocol: class {
func reloadTable(at index: Int)
}
更新 BookViewC
以符合 CustomAVPLayerProtocol
如下所示,
extension BookViewC: CustomAVPLayerProtocol {
func reloadTable(at index: Int) {
self.reloadTable(Offset: index)
}
}
然后更新 CustomAVPLayerC
class CustomAVPLayerC: AVPlayerViewController {
weak var delegate: CustomAVPLayerProtocol?
func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self.view)
if location.x < self.view.layer.frame.size.width / 2 {
print("Tapped Left")
} else {
let index = 1
self.delegate?.reloadTable(at: index)
}
}
}
}
最后在 BookViewC
中设置 CustomAVPLayerC
(当你初始化时)委托如下,
let customAVPLayerVC = CustomAVPLayerC()
customAVPLayerVC.delegate = self
我有一个名为 BookViewC 的 ViewController,它所做的只是显示 1 个视频。故事板包含一个名为 FullName 的 IBOutlet 和一个我用来显示视频的 UIView。我有一个功能,当你点击视频时,它应该会得到下一个视频。 当我获取下一个视频时,我总是得到 FullName 的 nil 值,它总是正确地获取第一个视频。
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
在 fullname 的 IBOutLet 上,我明白为什么,有没有办法解决这个问题?这是我用来清理问题的代码
class BookViewC: UIViewController, VideoViewDelegate{
@IBOutlet weak var VideoView: UIView!
@IBOutlet weak var FullName: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// This method queries the database for the latest video
ReloadTable(Offset: 0)
}
func reloadTable(Offset: Int) {
// Queries the database for video name
// Returns data in Json
DispatchQueue.main.async {
for Stream in Streams! {
if let fullname = Stream["fullname"] as? String {
// This below throws the nil error when getting the 2nd video
self.FullName.setTitle(fullname, for: .normal)
}
}
// Method below simply shows the video
self.PlayVideo(MediaHeight: Float(pic_height), MediaURL: s_image)
}
func PlayVideo(MediaHeight: Float, MediaURL: String) {
let movieURL = URL(string: MediaURL)
videoCapHeight.constant = CGFloat(MediaHeight)
streamsModel.playerView = AVPlayer(url: movieURL!)
streamsModel.MyAVPlayer.player = streamsModel.playerView
streamsModel.MyAVPlayer.videoGravity = AVLayerVideoGravity.resizeAspectFill.rawValue
streamsModel.MyAVPlayer.showsPlaybackControls = false
streamsModel.MyAVPlayer.view.frame = VideoView.bounds
VideoView.addSubview(streamsModel.MyAVPlayer.view)
self.addChildViewController(streamsModel.MyAVPlayer)
streamsModel.playerView?.isMuted = false
streamsModel.MyAVPlayer.player?.play()
}
}
当您点击视频时,它会转到此 class
class CustomAVPLayerC: AVPlayerViewController {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// I try to return to my original Class now
let BookC = BookViewC()
for touch in touches {
let location = touch.location(in: self.view)
if location.x < self.view.layer.frame.size.width / 2 {
print("Tapped Left")
}
else {
print("Tapped Right get next video")
// Offset is now 1 which gets the 2nd video
BookC.ReloadTable(offset: 1)
}
}
}
}
发生的事情是,一旦我转到 CustomAVPLayerC 控制器,BookViewC 中的所有 IBOutlet 都变为 nil,然后一旦我尝试返回,它就会给我错误。我能做些什么来解决这个问题或解决它吗?我显示的视频使用 AVPlayer 所以点击我必须去 CustomAVPLayerC Controller 。任何建议都会很棒。
这些行可能导致您的问题:
// I try to return to my original Class now
let BookC = BookViewC()
这是创建 BookViewC class 的 新 副本,而不是让您回到原来的状态。然后当您告诉它 reloadTable
它没有任何可以使用的视图。
解决此问题的方法是确保您当前的 BookViewC 对象(第一段代码中的 this
)可供视频播放器调用 reloadTable
方法。执行此操作的正常方法是通过 delegate
模式。
IBOutlets
为零,因为您的 BookVC
未从 .xib/storyboard
初始化。使用委托模式应该可以解决问题。以下是一个可以帮助实现这一目标的示例,
创建如下协议,
protocol CustomAVPLayerProtocol: class {
func reloadTable(at index: Int)
}
更新 BookViewC
以符合 CustomAVPLayerProtocol
如下所示,
extension BookViewC: CustomAVPLayerProtocol {
func reloadTable(at index: Int) {
self.reloadTable(Offset: index)
}
}
然后更新 CustomAVPLayerC
class CustomAVPLayerC: AVPlayerViewController {
weak var delegate: CustomAVPLayerProtocol?
func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self.view)
if location.x < self.view.layer.frame.size.width / 2 {
print("Tapped Left")
} else {
let index = 1
self.delegate?.reloadTable(at: index)
}
}
}
}
最后在 BookViewC
中设置 CustomAVPLayerC
(当你初始化时)委托如下,
let customAVPLayerVC = CustomAVPLayerC()
customAVPLayerVC.delegate = self