8

A ViewController has a UICollectionView. One of the cells contains JWVideoView. The app is frequently crashing on prepareForReuse in this cell.

There is no valuable info in the log. So I am having trouble figuring out the reason for the crash.

I've created a project example that demonstrates the crash. You can find it https://github.com/fuxlud/JWExample If the link between the cell and the videoView is removed, the crash will not happen.

import UIKit

class VideoArticleElementCollectionViewCell: UICollectionViewCell {

    // MARK: - Properties

    public var imageURL: String? { didSet { videoView?.imageURL = imageURL } }
    public var videoId: String? { didSet { videoView?.videoId = videoId } }

    @IBOutlet private var videoView: JWVideoView?

    // MARK: - Reuse

    override func prepareForReuse() {
        super.prepareForReuse() // Crashing here! (Thread 1: EXC_BAD_ACCESS (code=1, address=0x7e8))

        videoView?.stopPlayingVideo()
    }

    deinit {

        videoView?.stopPlayingVideo()
    }
}








import UIKit

class JWVideoView: UIView, JWPlayerDelegate {

    // MARK: Properties

    public var imageURL: String?
    public var videoId: String? { didSet { setupPlayer() } }

    private var jwPlayer: JWPlayerController?
    private let jwPlayerURL = "https://content.jwplatform.com/manifests/"
    private var didPause = false

    // MARK: - Initialization

    override init(frame: CGRect) {

        super.init(frame: frame)
        setup()
    }

    convenience init() {

        self.init(frame: CGRect.zero)
    }

    required init?(coder aDecoder: NSCoder) {

        super.init(coder: aDecoder)
        setup()
    }

    // MARK: - Setup

    private func setup() {}

    private func setupPlayer() {



            guard let videoId = self.videoId else { return }

            let playerURL = jwPlayerURL + videoId + ".m3u8"

            let configuration: JWConfig = JWConfig(contentURL: playerURL)
            configuration.controls = true
            configuration.autostart = true
//            configuration.premiumSkin = JWPremiumSkinGlow
            configuration.image = imageURL

            jwPlayer = JWPlayerController(config: configuration)

            if let player = jwPlayer {

                player.forceFullScreenOnLandscape = true
                player.forceLandscapeOnFullScreen = true
                player.view?.autoresizingMask = [.flexibleHeight, .flexibleWidth]
                player.view?.frame = bounds
                player.delegate = self
                player.volume = 0.0
                if let view = player.view { addSubview(view) }
            }

    }

    // MARK: - Orientation

    private func enableAllOrientation(enable: Bool) {

        if let delegate = UIApplication.shared.delegate as? AppDelegate {

//            delegate.shouldEnableLandscape = enable
        }
    }

    // MARK: API

    public func stopPlayingVideo() {

        enableAllOrientation(enable: false)

        if jwPlayer != nil {

            jwPlayer!.stop()
        }
    }

    // MARK: - JWPlayerDelegate

    internal func onFullscreen(_ status: Bool) {

        if status == false {

            let value = UIInterfaceOrientation.portrait.rawValue
            UIDevice.current.setValue(value, forKey: "orientation")
        }
    }

    internal func onPlayAttempt() {

        if jwPlayer != nil {

            enableAllOrientation(enable: true)


        }
    }

    internal func onPlay(_ oldValue: String) {

        if didPause {

            didPause = false
        }
    }

    internal func onPause(_ oldValue: String) {

        didPause = true

    }

    internal func onComplete() {

    }

}
Luda
  • 7,282
  • 12
  • 79
  • 139
  • 1
    When I was worked with JWPlayer, I have faced so many concerns or crashes. Trust me it's not our codding related stuff because JWPlayer is having so many known issues. I think you need to talk with the support team for an issue. In my application there 20K crash related to JWPlayer, it is more than the total number of the user. If your commented JWPlayer related code then everything worked as expected. – Hitesh Surani Jul 28 '19 at 08:04
  • Thanks, @iMHiteshSurani for your eye-opening and sad comment. – Luda Jul 28 '19 at 08:24
  • 1
    Sorry to hear that @Luda. Do you know what version of the SDK you're using? In the past couple months we've made significant improvements to our SDKs. – Kamil Sindi Jul 29 '19 at 13:48
  • 2
    @ksindi, OMG! VP Engineering at JW Player! Awesome for being responsive on StackOverflow. We are currently using `pod 'JWPlayer-SDK', '2.8.6'`. In addition, I've updated my question with more relevant code. If you prefer we can talk over email. – Luda Jul 30 '19 at 07:52
  • @Luda noticed the version you're using is < 3x. We've made significant stability improvements since then and no longer support 2x. Would it be possible to upgrade to the later version? For how see https://developer.jwplayer.com/sdk/ios/docs/developer-guide/migration/v3/. Our API is a lot more Swift friendly. – Kamil Sindi Jul 30 '19 at 14:26
  • @ksindi I'll upgrade – Luda Jul 31 '19 at 06:29
  • @ksindi Unfortuanlty the app is still crashing. – Luda Jul 31 '19 at 08:10
  • @Luda Will the app still crashes if you remove JWVideoView from the cell? – arturdev Aug 02 '19 at 07:34
  • could u share the error log pls even if it seems invaluable to u? – ugur Aug 04 '19 at 22:40
  • @arturdev I've created a project example that demonstrates the crash. You can find it https://github.com/fuxlud/JWExample If the link between the cell and the videoView is removed, the crash will not happen. – Luda Aug 05 '19 at 11:16
  • @ugur I've created a project example that demonstrates the crash. You can find it https://github.com/fuxlud/JWExample If the link between the cell and the videoView is removed, the crash will not happen. – Luda Aug 05 '19 at 11:16
  • 1
    @ksindi I've created a project example that demonstrates the crash. You can find it https://github.com/fuxlud/JWExample If the link between the cell and the videoView is removed, the crash will not happen. – Luda Aug 05 '19 at 11:17

1 Answers1

2

Based on your example project a saw the following issue inside your JWVideoView class: everytime you setting the videoId property it initiliaze the jwPlayer again, and also readds this view again to the stack.

1. Solution (remove the playerView and set the player to nil):

  private func setupPlayer() {

  jwPlayer?.view?.removeFromSuperview()
  jwPlayer = nil

  guard let videoId = self.videoId else { return }

  let playerURL = jwPlayerURL + videoId + ".m3u8"

  let configuration: JWConfig = JWConfig(contentURL: playerURL)
  configuration.controls = true
  configuration.autostart = true
  configuration.image = imageURL

  jwPlayer = JWPlayerController(config: configuration)
  jwPlayer?.forceFullScreenOnLandscape = true
  jwPlayer?.forceLandscapeOnFullScreen = true
  jwPlayer?.view?.autoresizingMask = [.flexibleHeight, .flexibleWidth]
  jwPlayer?.view?.frame = bounds
  jwPlayer?.delegate = self
  jwPlayer?.volume = 0.0

  if let view = jwPlayer?.view {
      addSubview(view)
  }

}

2. Solution (keep the player and the view instance and reset the configuration of the player)

  private func setupPlayer() {

  guard let videoId = self.videoId else { return }

  let playerURL = jwPlayerURL + videoId + ".m3u8"

  let configuration: JWConfig = JWConfig(contentURL: playerURL)
  configuration.controls = true
  configuration.autostart = true
  configuration.image = imageURL

  if jwPlayer == nil {

      jwPlayer = JWPlayerController(config: configuration)
      jwPlayer?.forceFullScreenOnLandscape = true
      jwPlayer?.forceLandscapeOnFullScreen = true
      jwPlayer?.view?.autoresizingMask = [.flexibleHeight, .flexibleWidth]
      jwPlayer?.view?.frame = bounds
      jwPlayer?.delegate = self
      jwPlayer?.volume = 0.0

      if let view = jwPlayer?.view {
          addSubview(view)
      }
  }else{
    //reset the configuration of the player here. but i dont now how this is possible with jwPlayer
  }

}

Klinki
  • 368
  • 1
  • 11