I have an AVAudioPlayer set up in my AppDelegate to play on startup. It continues playing throughout the app, but when I try to stop or play the player in a different class, the app crashes with EXC_BAD_ACCESS on that line.
AppDelegate.swift
import AVFoundation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var path = NSBundle.mainBundle().pathForResource("backgroundMusic", ofType: "wav")
var soundTrack = AVAudioPlayer()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
soundTrack = AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: path), error: nil)
soundTrack.numberOfLoops = -1
soundTrack.volume = 0.35
soundTrack.play()
return true
}
OtherClass.swift
func aFunction() {
let appDelegate = AppDelegate()
appDelegate.soundTrack.stop() //Here is where the app crashes. Same with .play()
}
Thanks for any help!
by doing AppDelegate() you are creating a new instance of app delegate; one which the variables haven't been initiated. You want to get the UiApplications shared delegate:
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
Related
I need to loop a video in an Apple TV app, and I really would prefer to use TVJS so that we can update easily server side. However, when I loop the video, it shows the playback controls every time, and this is not ideal.
I see that AVPlayerViewController has a showsPlaybackControls bool that can be set to false, and is true by default, but the TVJS Player Class does not seem to have the same available to it.
What I am curious about is if there is a way that from the AppDelegate I can change that default from true to false so that the playbackControls never ever show? I have included my AppDelegate as well below. Thanks in advance!
import UIKit
import TVMLKit
import AVFoundation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, TVApplicationControllerDelegate {
var window: UIWindow?
var appController: TVApplicationController?
static let TVBaseURL = "http://localhost:3000/"
static let TVBootURL = "\(AppDelegate.TVBaseURL)assets/tv.js"
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
let appControllerContext = TVApplicationControllerContext()
guard let javaScriptURL = NSURL(string: AppDelegate.TVBootURL) else {
fatalError("unable to create NSURL")
}
appControllerContext.javaScriptApplicationURL = javaScriptURL
appControllerContext.launchOptions["BASEURL"] = AppDelegate.TVBaseURL
appController = TVApplicationController(context: appControllerContext, window: window, delegate: self)
return true
}
}
I'm developing an App that it's data is from a URL, here's a sample code that I'm using
AppDelegate.swift
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var fromUrl: String!
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject)-> Bool {
print("Host: \(url.host!)")
self.fromUrl = url.host!
return true
}
ViewController.swift
import UIKit
class ViewController: UIViewController {
let appDelegate = AppDelegate()
override func viewDidLoad() {
super.viewDidLoad()
print(appDelegate.fromUrl)
}
It's is logging the url.host from app delegate. But when i try to log the value of fromUrl from the ViewController.swift it's returning nil. What do you think seems to be the problem? Thanks!
When you declare let appDelegate = AppDelegate() in ViewController you are actually instantiating another instance of AppDelegate. That is not the same instance that you are using as you actual ApplicationDelegate. Try getting that reference by using:
if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate {
print(appDelegate.fromUrl)
}
I have two test apps: App1 & App2.
App1 takes String from the text field and triggers method:
#IBAction func openApp(sender: AnyObject) {
let url1 = ("app2://com.application.started?displayText="+textToSend.text!)
let url2 = url1.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
UIApplication.sharedApplication().openURL(NSURL(string: url2!)!)
}
Which actually opens App2 which has only label which should change to the text sent through the url, code is within AppDelegate.swift:
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
let url = url.standardizedURL
let query = url?.query
ViewController().labelToDisplayResult.text = query
return true;
}
Unfortunately the line where I am trying to pass result of the URL to the actual label is giving me this error:
EXC_BAD_INSTRUCTION (CODE=EXC_I386_INVOP SUBCODE=0x0)
However I have all the data in the App2 for sure as I can see their values in debugger:
url NSURL "app2://com.application.started?displayText=564315712437124375" 0x00007fa4e3426320
query String? "displayText=564315712437124375"
Any idea why I am getting this error?
Thanks...
Your error
ViewController().labelToDisplayResult.text = query
ViewController() Create a new instance of ViewController,not the one loaded from storyboard.I guess labelToDisplayResult is an outlet, so it is nil,so you get EXC_BAD_INSTRUCTION (CODE=EXC_I386_INVOP SUBCODE=0x0)
This is what I usually do to handle openURL scheme,need to think about two states:
Target App is launched before,so when open url happen,the target app is in background or inactive state
Target App is not launched,so when open url happen,the target app is not running at all
In Appdelegate
class AppDelegate: UIResponder, UIApplicationDelegate {
var openUrl:NSURL? //This is used when to save state when App is not running before the url trigered
var window: UIWindow?
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
let url = url.standardizedURL
NSNotificationCenter.defaultCenter().postNotificationName("HANDLEOPENURL", object:url!)
self.openUrl = url
return true;
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
return true
}
}
Then in the ViewController handle openURL
class ViewController: UIViewController {
#IBOutlet weak var testLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "handleOpenURL:", name:"HANDLEOPENURL", object: nil)
let delegate = UIApplication.sharedApplication().delegate as? AppDelegate
if let url = delegate?.openUrl{
testLabel.text = url.description
delegate?.openUrl = nil
}
}
func handleOpenURL(notification:NSNotification){
if let url = notification.object as? NSURL{
testLabel.text = url.description
}
}
deinit{
NSNotificationCenter.defaultCenter().removeObserver(self, name: "HANDLEOPENURL", object:nil)
}
}
Using: XCode 7, iPhone 5 (iOS 8.3), WiFi, Reachability (check the internet connection).
While my app is in background and I click to open my app it checks the conncetion and load some functions and in 1 of the functions I try to sign:
imageView.image = UIImage(named: "imagename")
error: fatal error: unexpectedly found nil while unwrapping an Optional value
This happens only when my app change an IBOutlet value in applicationWillEnterForeground with function to primary view controller
self.viewController.functionName()
class AppDelegate: UIResponder, UIApplicationDelegate {
var viewController:ViewController = ViewController()
func applicationWillEnterForeground(application: UIApplication) {
self.viewController.checkConn()
}
}
checkConn() check the connection with Reachability and change IBOutlets values like .image and .text
Is there any way to fix it?
After a lot of tests I found this method which works great:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var viewController:ViewController?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
viewController = self.window!.rootViewController as? ViewController
return true
}
func applicationWillEnterForeground(application: UIApplication) {
viewController!.checkConn()
}
}
I am assuming that this is where your crash is happening.
imageView.image = UIImage(named: "imagename")
If you are using "Images.xcassets" to manage your image files. Make sure that "imagename" exists.
So I have a music that starts playing in the AppDelegate (when the app is loaded basically), and I want to make it stop once I press a button on my settings scene that has its own ViewController class.
How can this be achieved? How can I access the variable I have on my appDelegate class that starts the music?
Here's the code for starting the music in AppDelegate:
var themeAudioURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("theme", ofType: "mp3")!)
var themePlayer = AVAudioPlayer()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
themePlayer = AVAudioPlayer(contentsOfURL: themeAudioURL, error: nil)
themePlayer.volume = 0.05
themePlayer.numberOfLoops = -1
themePlayer.play()
return true
}
You can pass player further to the next scene. You can do this in prepare for segue method. Alternatively you can get an app delegate in another view controller and cast it to your appdelegate implementation.