0

I want to fetch a video from a url and play it inside a view on tap of a button.

I have a moviePlayer which plays a video from a URL. Everything looks good but when I click on Back or Next button (i.e. change the viewController) the video continues to play (as I am still able to hear the audio on the new screen.

So I thought of add moviePlayer.Stop() on viewDidDismiss. It works good on first view change, but when I come back to the moviePlayer view and click next I find a nil error at moviePlayer.Stop() (as the movie is already stopped). Can someone help me understand how to do this?

import UIKit import MediaPlayer

class InformationViewController: UIViewController {

@IBOutlet var thumbnailImage: UIImageView!
@IBOutlet var videoPlayerView: UIView!

@IBOutlet var controlBtn: UIButton!

var moviePlayer:MPMoviePlayerController!
var url:NSURL = NSURL(string: "http://jplayer.org/video/m4v/Big_Buck_Bunny_Trailer.m4v")!


override func viewDidLoad() {
    super.viewDidLoad()

}

func videoThumbnailIsAvailable(notification: NSNotification){

    if let player = moviePlayer{
        println("Thumbnail is available")
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: "videoThumbnailIsAvailable:",
            name: MPMoviePlayerThumbnailImageRequestDidFinishNotification,
            object: nil)
        /* Capture the frame at the third second into the movie */
        let thirdSecondThumbnail = 3.0

        /* We can ask to capture as many frames as we
        want. But for now, we are just asking to capture one frame
        Ask the movie player to capture this frame for us */
        moviePlayer.requestThumbnailImagesAtTimes([thirdSecondThumbnail],
            timeOption: .NearestKeyFrame)

        /* Now get the thumbnail out of the user info dictionary */
        let thumbnail =
        notification.userInfo![MPMoviePlayerThumbnailImageKey] as? UIImage

        if let imageR = thumbnail{

            /* We got the thumbnail image. You can now use it here */
            println("Thumbnail image = \(imageR)")
            //println(UIImage(data: imageR))
            thumbnailImage.image = imageR
        }
    }
}

@IBAction func controlBtn(sender: AnyObject) {
    controlBtn.alpha = 0
    moviePlayer = MPMoviePlayerController(contentURL: url)
    let frameWidth = self.videoPlayerView.frame.size.width
    let frameHeight = self.videoPlayerView.frame.size.height

    //moviePlayer.view.frame = CGRect(x: 24, y: 18, width: frameWidth, height: frameHeight)

    self.videoPlayerView.addSubview(moviePlayer.view)


    //     Send button backword
    self.videoPlayerView.sendSubviewToBack(moviePlayer.view)
    moviePlayer.fullscreen = false
    moviePlayer.controlStyle = MPMovieControlStyle.Embedded

    // Pure Visual Format Language style (http://stackoverflow.com/questions/26180822/swift-adding-constraints-programmatically)
    (moviePlayer.view).setTranslatesAutoresizingMaskIntoConstraints(false)
    let views = ["view": videoPlayerView, "videoView": moviePlayer.view]

    var constH = NSLayoutConstraint.constraintsWithVisualFormat("H:[view]-(<=0)-[videoView(\(frameWidth))]", options: .AlignAllCenterY, metrics: nil, views: views)
    view.addConstraints(constH)
    var constW = NSLayoutConstraint.constraintsWithVisualFormat("V:[view]-(<=0)-[videoView(\(frameHeight))]", options: .AlignAllCenterX, metrics: nil, views: views)
    view.addConstraints(constW)

}

override func viewDidDisappear(animated: Bool) {
        moviePlayer.stop()

}
}

Any help would be appreciated. Thanks.

NS1518
  • 838
  • 1
  • 8
  • 23

1 Answers1

3

From your code it looks like your moviePlayer property isn't defined until the controlBtn(sender) action is called, so if you navigate away from this view controller without pushing that button first, moviePlayer will be nil when the view controller disappears.

override func viewDidDisappear(animated: Bool) {
    super.viewDidDisappear(animated)  ///< Don't for get this BTW!

    if let player = self.moviePlayer {
        player.stop()
    }
}

Furthermore, your moviePlayer property should be an optional instead of an implicitly unwrapped optional. That's the point of optionals—they prevent you from making these mistakes and having crashes like the one you're experiencing.

var moviePlayer: MPMoviePlayerController?
Patrick Lynch
  • 2,742
  • 1
  • 16
  • 18
  • Thank you Patrick. It worked. But can you please explain what super.viewDidDissapear(animated) is to be added if I already have it in the override func? Also, how "let player" helped and not the one I had it in my code? I am still learning so would be great to know how that worked. Thanks again. – NS1518 Jun 06 '15 at 21:06
  • 1
    There's not enough characters allowed in a comment to fully explain all of these issues, but suffice it to say that when you override a view controller's lifecycle methods (`viewDidLoad`, `viewDidAppear:`, etc.), you always have to call `super`. Beyond that, be sure to thoroughly read the documentation on view controllers and Swift. :) https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html – Patrick Lynch Jun 06 '15 at 21:24