IOS Swift Как фатальная ошибка разворачивает необязательное значение

У меня есть ViewController с именем BookViewC, и все, что он делает, это отображает 1 видео. Раскадровка содержит IBOutlet под названием FullName и UIView, который я использую для показа видео. У меня есть функциональность, когда вы нажимаете на видео, оно должно получить следующее видео. Я всегда получаю нулевое значение для FullName, когда получаю следующее видео, оно всегда правильно получает первое видео .

Тема 1: Неустранимая ошибка: неожиданно найдено nil при развертывании необязательного значения

в IBOutLet для fullname, почему я понимаю, есть ли способ обойти это? Вот мой код, чтобы прояснить ситуацию

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 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, все IBOutlets из BookViewC становятся нулевыми, а затем, когда я пытаюсь вернуться, это дает мне ошибку. Есть ли что-нибудь, что я могу сделать, чтобы исправить это или обойти это? Видео, которые я показываю, используют AVPlayer, поэтому при нажатии я должен перейти к контроллеру CustomAVPLayerC. Любые предложения были бы замечательными.


person user1591668    schedule 11.04.2018    source источник
comment
При возврате к основному классу просто удалите добавленный вами Subview вместо создания нового экземпляра mainController.   -  person iOS Geek    schedule 11.04.2018


Ответы (2)


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
person Kamran    schedule 11.04.2018

Эти строки, вероятно, вызывают вашу проблему:

// I try to return to my original Class now
let BookC = BookViewC()

Это создает новую копию класса BookViewC, не возвращая вас к оригиналу. Когда вы затем сообщите об этом reloadTable, за ним не будет никакого представления, с которым можно работать.

Чтобы исправить это, убедитесь, что ваш текущий объект BookViewC (this в вашем первом фрагменте кода) доступен для видеопроигрывателя для вызова метода reloadTable. Обычный способ сделать это — использовать шаблон delegate.

person The Dark    schedule 11.04.2018