I am trying to make this Simon game app for practicing. As shown in the right code in the image attached, the author had 4 players for each color respectively and therefore, 4 delegates.
I tried to simplify it a little bit by using only one player, as shown in the left code. However, I got the error saying "Unexpectedly found nil while unwrapping an optional value". I don't understand why it would be optional as I unwrapped player using !.
What is the reason for the error?
Thanks.
You are trying to assign a value to a property of an object, while the object is nil and not yet initialized.
Move those lines of code
player.delegate = self
player.numberOfLoops = 0
to the playSound function
func playSound(soundName: String) {
let url = Bundle.main.url(forResource: soundName, withExtension: "wav")
player = try! AVAudioPlayer(contentsOf: url!)
player.delegate = self
player.numberOfLoops = 0
player.play()
}
Related
I'm using AVKit to play a youtube URL.
I have this code inside a button action:
#IBAction func trailerButtonAction(_ sender: Any) {
guard let youtubeUrl = youtubeURL else { return }
let player = AVPlayer(url: youtubeUrl)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
present(playerViewController, animated: true) {
player.play()
}
}
The URL is valid, but when I press the button, the video doesn't stop loading and I'm getting this message on Debug area:
nw_endpoint_flow_copy_multipath_subflow_counts Called on non-Multipath connection
Edit:
I found that AVPlayer doesn't support youtube URL
I would say this log isn't necessarily relevant. I was getting this error when trying to playback on the simulator but it wasn't happening on a real device.
One workaround would be to use a 12.4.x simulator as it does not exhibit this issue. Only the 13.x simulators are showing this error. It happens to repeatedly that it slows down Simulator to a craw until all requested tracks have been buffered.
To combat this while testing, I am either not turning on AVPlayer or I am only buffering a short track.
To cut down on the number of errors try initing your AVPlayer like so:
var avPlayer : AVPlayer = AVPlayer()
This may cut down the errors by 30%.
I know it seems quite straightforward, but in a weird way AVAudioPlayer does not play audio file. I have this code. It is not go through catch and still sound does not play. I've checked on physical device, simulator and also checked sound volume. But still I can't hear sound.
//in ViewController as a property
let soundEffect: AVAudioPlayer!
//in viewDidLoad
let path = Bundle.main.path(forResource: "success.mp3", ofType:nil)!
let url = URL(fileURLWithPath: path)
do {
soundEffect = try AVAudioPlayer(contentsOf: url)
soundEffect.prepareToPlay()
soundEffect.play()
} catch let error as NSError {
print(error.description)
}
I also tried let path = Bundle.main.path(forResource: "success", ofType:"mp3")! but it didn't make any difference.
Try making your AVAudioPlayer an instance variable. otherwise soundEffect is deallocated at the end of the do loop.
I am working on a simple game in Swift 4, Xcode 9 Beta 6, and I get an error when attempting to load an Audio File from the same URL many times. Let me show you what I mean; I have a code that looks a little like this.
guard let url = Bundle.main.url(forResource: soundName, withExtension: ext) else {
return nil
}
do {
player = try AVAudioPlayer(contentsOf: url)
player.prepareToPlay()
} catch let error {
print("Could not create AVAudioPlayer with url: \(url.absoluteString)")
return nil
print("Error: \(error.localizedDescription")
}
Note: soundName and ext are String objects composing the name of the local audio file. player is a property of the type AVAudioPlayer.
The game creates a sound using this code, which works perfectly at first, but after a while, it kind of gets lazy and the player = try AVAudioPlayer(contentsOf: url) fails and prints:
Could not create AVAudioPlayer with url: url here
Error: The operation couldn't be completed. (NSOSStatusErrorDomain error -42.)
Anyone has any ideas?
EDIT 1:
I loaded the content of the URL into a Data object by using let data = try Data(contentsOf: url) and that seems to have fix the issue. I am not making it as resolved because I still wish to know what is wrong with using just a URL and why it stops working after loading the same URL several times. Additionally, loading the contents into a binary Data object first might take more resources and time?
I set the userData of my SKSpriteNode in the scene editor:
Then I tried to get it, using:
let sprite:SKSpriteNode = self.childNode(withName: "sprite") as? SKSpriteNode
let numero:Int = sprite.userdata?.valueForKey("numero") as! Int
But I got nil value : "fatal error: unexpectedly found nil while unwrapping an Optional value"
I also tried to init the userData with:
sprite.userData? = NSMutableDictionary()
But same result...
Probably also your sprite is nil:
try to search your sprite with the optional binding (if let) and the "//" before sprite.
if let sprite = self.childNode(withName: "//sprite") as? SKSpriteNode {
let numero:Int = sprite.userdata?.valueForKey("numero") as! Int
} else {
print("I cannot find sprite..")
}
It performs a recursive search from its current position.
Check the API reference here.
I have a subclass of SKSpriteNode called 'backgroundMusic' that consists of a SKSpriteNode and a AVAudioPlayer file. The objective is to completely delete 'backgroundMusic' after i instantiate it. I try to do :
backgroundMusic.removeFromParent()
but it only removes the SKSpriteNode and not the AVAudioPlayer.
The main issue is that inside of this subclass, I call a bunch of functions within other functions, and when i try to empty the subclass by:
backgroundMusic = nil
the process of calling all the functions still is occurring and causes issues when i re-instantiate it. What i believe will work is if I delete 'backgroundMusic' completely, which will stop the function calling process, and then later re-instantiate it when i need to, it should work fine with no issues. How can I do this?
EDIT I tried:
self.delete(backgroundMusic)
and it crashed the application. Should I use this? If so how?
This happened because you havent configure Audio Session
Some code for playing:
import AVFoundation
var audioPlayer = AVAudioPlayer()
func playAudio() {
// Set the sound file name & extension
let alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("Flip 02", ofType: "wav")!)
// Preperation
try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, withOptions: AVAudioSessionCategoryOptions.MixWithOthers)
try! AVAudioSession.sharedInstance().setActive(true)
// Play the sound
do {
try audioPlayer = AVAudioPlayer(contentsOfURL: alertSound)
audioPlayer.prepareToPlay()
audioPlayer.play()
} catch {
print("there is \(error)")
}
}
Details from the docs:
AVAudioSessionCategoryOptionMixWithOthers
Mixes audio from this session with audio from other active sessions.
Valid only if the session category is
AVAudioSessionCategoryPlayAndRecord or AVAudioSessionCategoryPlayback.
(Implicit if the session category is AVAudioSessionCategoryAmbient.)
If you activate your session while using this option, your app’s audio
will not interrupt audio from other apps (such as the Music app). If
not using this option (or a category that is implicitly mixable),
activating your session will interrupt other nonmixable sessions.
To stop you can do:
do {
try AVAudioSession.sharedInstance().setActive(false)
} catch let error as NSError {
print(error.localizedDescription)
}