dismissMoviePlayerViewControllerAnimated not working in Swift - swift

There don't seem to be any SO posts on dismissMoviePlayerViewControllerAnimated in Swift so I guess I'll kick things off.
I have a table cell, when you do a long press on it, it displays a video. When the video ends, my goal is to take the user back to the table view. That last piece is the bit that's not working.
Any help here would be greatly appreciated. I've read through the Apple docs and some posts about this in Objective-C. Seems that the answer is to run dismissMoviePlayerViewControllerAnimated, a method on UIViewController but it's not working.
import UIKit
import MediaPlayer
class ViewController: UIViewController {
var moviePlayer:MPMoviePlayerController!
#IBOutlet weak var longPressView: UIView!
let longPressRec = UILongPressGestureRecognizer()
func longPressedView() {
playVideo()
}
func videoHasFinishedPlaying(notification: NSNotification){
println("Video finished playing")
self.dismissMoviePlayerViewControllerAnimated()
// not returning me to the ViewController
}
func playVideo() {
// get path and url of movie
let path = NSBundle.mainBundle().pathForResource("IMG_8602", ofType:"MOV")
let url = NSURL.fileURLWithPath(path!)
moviePlayer = MPMoviePlayerController(contentURL: url)
// construct the views
moviePlayer.view.frame = self.view.bounds
self.view.addSubview(moviePlayer.view)
moviePlayer.fullscreen = true
// remove controls at top and bottom of video
moviePlayer.controlStyle = MPMovieControlStyle.None
// add event observer for videoHasFinsihedPlaying
NSNotificationCenter.defaultCenter().addObserver(self, selector: "videoHasFinishedPlaying:",
name: MPMoviePlayerPlaybackDidFinishNotification, object: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
longPressRec.addTarget(self, action: "longPressedView")
longPressView.addGestureRecognizer(longPressRec)
longPressView.userInteractionEnabled = true
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Your code does not work because you are using MPMoviePlayerController instead of MPMoviePlayerViewController.
You are calling:
self.dismissMoviePlayerViewControllerAnimated()
but there is no MPMoviePlayerViewController to dismiss. That's why nothing happens.
If you prefer to use MPMoviePlayerController (as in the code you posted), after adding manually its view, you also have to manually remove it.

Related

AppleTV - tvos - Hybrid app using native and TVMLKIT - Can't back to native app

I'm a beginner on TVOS.
I'd like to create an hybrid app on AppleTV using a native app and TVMLKIT.
My native application is just a simple native app with buttons (using swift).
When we click on a button, I launch a a javascript app using TVLMKIT and TVJS.
My TVJS as uses the Player to display a video.
When the video is over, I want to close the TVJS app and back to the native ViewController.
My problem is that when I back to native app, I loose the focus on my native View (the app is frozen).
native ViewController:
import UIKit
import TVMLKit
class ViewController: UIViewController, TVApplicationControllerDelegate {
var window: UIWindow?
var appController: TVApplicationController?
var appControllerContext = TVApplicationControllerContext();
static let TVBaseURL = "http://localhost:9001/"
static let TVBootURL = "\(ViewController.TVBaseURL)/client/js/application.js"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet weak var label: UILabel!
#IBOutlet weak var viewAd: UIView!
#IBAction func clickOnlaunchAd(sender: AnyObject) {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
guard let javaScriptURL = NSURL(string: ViewController.TVBootURL) else {
fatalError("unable to create NSURL")
}
appControllerContext.javaScriptApplicationURL = javaScriptURL
appControllerContext.launchOptions["BASEURL"] = ViewController.TVBaseURL
appController = TVApplicationController(context: appControllerContext, window: window,delegate: self)
}
#IBAction func clickOnChangeText(sender: AnyObject) {
label.text = "changed";
}
func appController(appController: TVApplicationController, didStopWithOptions options: [String : AnyObject]?) {
self.setNeedsFocusUpdate()
self.updateFocusIfNeeded()
}
func appController(appController: TVApplicationController, evaluateAppJavaScriptInContext jsContext: JSContext){
let notifyEventToNative : #convention(block) (NSString!) -> Void = {
(string : NSString!) -> Void in
print("[log]: \(string)\n")
self.appController?.stop()
}
jsContext.setObject(unsafeBitCast(notifyEventToNative, AnyObject.self), forKeyedSubscript: "notifyEventToNative")
}
}
Just before calling "notifyEventToNative" from my TVJS, I call "navigationDocument.clear();" to clear the TVML view.
I can see my native app but I can't interact with it.
Any ideas?
Thanks.
I also had the same problem. I was opened a TVML document from the UIViewController. And I also lost the focus. So, first of all I can advice you to override var called preferredFocusedView in your ViewController. In this method you can return reference to viewAd. But the better solution would be to wrap your ViewController into the TVML-item (with the TVMLKit framework). In that case I hope that you will have no problems with focus because you will use TVML during the whole application.

Why is my prepareForSegue code activating the wrong button?

I'm learning how to program and am playing with a Swift project in Xcode. The main storyboard has two view controllers. The first view controller is simply called ViewController and the second view controller is called HelpScreenViewController.
In ViewController I have a "help" button that switches the user to HelpScreenViewController. This button uses a segue called "goToHelpScreenSegue".
In HelpScreenViewController I have three buttons:
"Close" button to dismisses the view (no segue used)
"Send Feedback" button to generate a new email in the Mail app (no segue used)
"Reset Game" button to call a function that is coded within the first ViewController. This third button uses a segue called "resetGameSegue".
What I'm trying to do is...
...Get the "Reset Game" button on the HelpScreenViewController to reset the game by calling a function that's coded within the first view controller.*
To try and get this to work the way I want, I've used the following code:
WITHIN first main ViewController
import UIKit
import iAd
import AdSupport
import AVFoundation //audio
import GameplayKit
class ViewController: UIViewController, ADBannerViewDelegate, MyResetGameProtocol {
#IBOutlet weak var Banner: ADBannerView!
#IBOutlet weak var buttonA: UIButton!
#IBOutlet weak var buttonB: UIButton!
#IBOutlet weak var buttonC: UIButton!
#IBOutlet weak var buttonD: UIButton!
#IBOutlet weak var labelQuestion: UILabel!
#IBOutlet weak var labelScore: UILabel!
#IBOutlet weak var labelTotalQuestionsAsked: UILabel!
#IBOutlet weak var labelFeedback: UILabel!
#IBOutlet weak var buttonNext: UIButton!
var score :Int! = 0
var totalquestionsasked :Int! = 0
var allEntries : NSArray!
var shuffledQuestions: [AnyObject]!
var nextQuestion = -1
var currentCorrectAnswerIndex : Int = 0
var audioPlayer = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.Banner?.delegate = self
self.Banner?.hidden = true
LoadAllQuestionsAndAnswers()
if #available(iOS 9.0, *) {
shuffledQuestions = GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(allEntries as [AnyObject])
nextQuestion++
LoadQuestion(nextQuestion)
// Fallback on earlier versions
}else{
let randomNumber = Int(arc4random_uniform(UInt32(allEntries.count)))
LoadQuestionPreiOS9(randomNumber)
}
LoadScore()
AdjustInterface()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let viewController = segue.destinationViewController as! HelpScreenViewController
viewController.controller = self
}
func ResetGame() {
PlaySoundReset()
score = 0
totalquestionsasked = 0
SaveScore()
LoadScore()
}
func PlaySoundReset()
{
let alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("pcbeep", ofType: "wav")!)
do {
audioPlayer = try AVAudioPlayer(contentsOfURL: alertSound)
} catch {
}
audioPlayer.prepareToPlay()
audioPlayer.play()
}
func SaveScore()
{
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setInteger(score, forKey: "Score")
defaults.setInteger(totalquestionsasked, forKey: "Out of")
}
func LoadScore()
{
let defaults = NSUserDefaults.standardUserDefaults()
score = defaults.integerForKey("Score")
totalquestionsasked = defaults.integerForKey("Out of")
labelScore.text = "Score: \(score)"
labelTotalQuestionsAsked.text = "out of \(totalquestionsasked)"
}
and so on....
WITHIN the second HelpScreenViewController
import UIKit
protocol MyResetGameProtocol {
func ResetGame()
}
class HelpScreenViewController: UIViewController, MyResetGameProtocol {
var controller: MyResetGameProtocol? // reference to the delegate alias First Controller
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
#IBAction func SendFeedback(sender: AnyObject) {
UIApplication.sharedApplication().openURL(NSURL(string: "mailto:feedback#felice.ws?")!)
}
#IBAction func DismissView(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil) }
#IBAction func buttonResetGame(sender: AnyObject) {
controller.ResetGame()
}
}
Now, at the moment with the above code what happens is that if the user taps the "help" button in the first main ViewController (i.e. goToHelpScreenSegue), not only does it take the user to the help screen, but it also calls the function I want activated when the user taps on the "Reset Game" button instead. That is, at the moment, it's the "help" button that resets the game before taking the user to the help screen.
Now, within the help screen, the first two buttons work normally (but they're not using segues). Tapping on the third button (the Reset Game one) simply returns the user back to the main screen. It doesn't call the function, doesn't reset the game.
I've lost count of the times I've changed the code around to try and get it to work right, but I've obviously missed something really obvious.
In particular, I've tried using the following code instead within the main ViewController:
override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
if segue?.identifier == "resetGameSegue" {
let viewController = segue!.destinationViewController as! HelpScreenViewController
viewController.controller = self
}
However, this results in nothing happening. What I mean is that the button on the main screen works properly (taking the user to the help screen and not incorrectly calling the resetGame function). And, within the help screen the first two buttons work as expected, but the "Reset Game" button just returns the user to the first screen but without calling the ResetGame function.
I also tried removing the IBActions from both my code and the connections inspector for the "Reset Game" button, but that made no difference either.
Any assistance would be most appreciated as I'm just not getting it! :(
I'm agree with MikeG, that you should probably learn about how delegates should be implemented. But the thing you're doing wrong inside this code is that you're not actually calling ResetGame() function on your delegate. Try to implement your #IBAction function in this way:
#IBAction func buttonResetGame(sender: AnyObject) {
controller?.ResetGame()
}
And yeah, if I understand your logic correctly your HelpScreenViewController should not implement MyResetGameProtocol cause your ViewController is the one who's implementing it.

How to pass a string between viewcontrollers with out the use of a SEGUE

Recently I have been making a app where you can create and quiz yourself on definitions or anything for that matter. I pass data to the next view after it the user hits the create button to make the title of the new notecard. The code I am using right now for that is:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let DestViewController: Card1 = segue.destinationViewController as! Card1
DestViewController.Content = Notetitle.text!
self.saved = self.Notetitle.text!
}
All of that works but, it will only work if I have a segue between viewcontrollers. I need to be able to pass that data with out a segue because I want the user to be able to create as many notecards as they want and the way I am trying to do that now is by using this code to make a copy of the UIView and then put in the new data (a master view). The new view can only be create using an IBAction. The prepare for segue I cannot use in the IBAction because it is it's own override function.
This is the code I am using to make a the new view:
let newCard =
self.storyboard!.instantiateViewControllerWithIdentifier("Main")
self.presentViewController(newCard, animated: true, completion:nil)
My hope is that I will be able to make a new view and then pass in the data pass in the data that the user just made to go on the notecard. (Hope this makes any sense at all)
MAIN TOPICS: -Create a new view and pass in new data Problem: Can pass data without a segue dont have one :/ -Be able to pass data between view controllers without a segue :)
I am new to all of this about 5 months. All of my code is in swift. Take it easy on me please. Feel free to ask me with any questions or comments. I have already posted a question on this but I didnt get an answer so have at it.
Thanks, Lucas Mazza
Don't use global variables unless you really need to. Making global static singleton's does not follow best practices. For more information read: What is so bad about singletons?
A better solution
You can use the protocol delegate pattern. I've actually written an article on this topic here:
https://www.codebeaulieu.com/36/Passing-data-with-the-protocol-delegate-pattern
You'll need a protocol that defines a function that will accept data. Then your other view controller will need to implement the delegate. If you need step-by-step details see the link provided above, alternatively you can simply download the project below and examine the code.
Download Working Example Project
Here's the code to make your protocol-delegate pattern work:
View Controller 1:
class ViewController: UIViewController, PresentedViewControllerDelegate {
#IBOutlet weak var textOutlet: UILabel!
#IBAction func doPresent(sender: AnyObject) {
let pvc = storyboard?.instantiateViewControllerWithIdentifier("PresentedViewController") as! PresentedViewController
pvc.data = "important data sent via delegate!"
pvc.delegate = self
self.presentViewController(pvc, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func acceptData(data: AnyObject!) {
self.textOutlet.text = "\(data!)"
}
}
View Controller 2:
import UIKit
// place the protocol in the view controller that is being presented
protocol PresentedViewControllerDelegate {
func acceptData(data: AnyObject!)
}
class PresentedViewController: UIViewController {
// create a variable that will recieve / send messages
// between the view controllers.
var delegate : PresentedViewControllerDelegate?
// another data outlet
var data : AnyObject?
#IBOutlet weak var textFieldOutlet: UITextField!
#IBAction func doDismiss(sender: AnyObject) {
if textFieldOutlet.text != "" {
self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
}
override func viewDidLoad() {
super.viewDidLoad()
print("\(data!)")
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
if self.isBeingDismissed() {
self.delegate?.acceptData(textFieldOutlet.text)
}
}
}

Streaming .m3u8 using MPMoviePlayerController does not work

I used the example in how to play a local video and tried to modify for use on .m3u8 file. I am unable to make it work. I get a blank screen. I confirmed that the file was ok by testing on VLC. Any help would be appreciated.
Here is the code:
import UIKit
import MediaPlayer
class ViewController: UIViewController {
var moviePlayer : MPMoviePlayerController?
override func viewDidLoad() {
super.viewDidLoad()
playVideo()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
private func playVideo() {
let path = "http://qthttp.apple.com.edgesuite.net/1010qwoeiuryfg/sl.m3u8"
if let
//path = NSBundle.mainBundle().pathForResource("movie", ofType:"m4v"),
url = NSURL(fileURLWithPath: path),
moviePlayer = MPMoviePlayerController(contentURL: url) {
self.moviePlayer = moviePlayer
moviePlayer.view.frame = self.view.bounds
moviePlayer.prepareToPlay()
moviePlayer.scalingMode = .AspectFill
self.view.addSubview(moviePlayer.view)
} else {
debugPrintln("Ops, something wrong when playing .m3u8 file")
}
}
}
You've specified your url incorrectly. Change it to this:
url = NSURL(string:path)

UIWebView is not displaying (Swift)

I am just trying to create a simple webview inside a view controller.
Here is my code:
import UIKit
class test:UIViewController{
#IBOutlet weak var myWebView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var myString = "http://www.google.com"
let myURL = NSURL(string: myString)
let myReq = NSURLRequest(URL: myURL)
myWebView.loadRequest(myReq)
println(myWebView.loading)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I'm not getting any errors, simply a white screen. The loading check returns false. It seems like it should be the outlet connection, but I am sure I've made the proper connection. I ctrl-dragged the blue UIWebView element from storyboard into the class as the UIWebView! object and named it myWebView. The circle is filled in on the swift file indicating a connection, and they match up in the connections on the storyboard.
This code originally worked fine for me, but now it does not. I tried creating a completely new project and it still is not working. Adding the UIWebViewDelegate protocol to the class didn't work I've looked at the solutions on the following links, but they do not apply:
link1
link2
I'm out of ideas. Anyone got anything?
Thanks!
This is what you wan in viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var myWeb = UIWebView(frame: CGRect(x: 40, y: 100, width: 240, height: 128))
var myString = "http://www.google.com"
let myURL = NSURL(string: myString)
let myReq = NSURLRequest(URL: myURL!)
myWeb.loadRequest(myReq)
view.addSubview(myWeb)
println(myWeb.loading)
}
Be careful, you have another web view (called myWebView) from the storyboard, as an outlet and that is not used. By writing the above code you create a new web view programmatically (called myWeb).