Unexpectedly found nil while implicitly unwrapping an Optional value AVAUDIO Player SWIFT - swift

I am currently downloading an m4a file from firebase and trying to play the file with AVAudio Player.
How the system works
Get path of downloaded file as String
let pathForAudio: String = UserDefaults.standard.string(forKey: "path") ?? "There is no path for the audio"
Convert to URL
let url = URL(string: pathForAudio)
Pass URL into AVAUDIOPLAYER Function
soundPlayer = try AVAudioPlayer(contentsOf: url!)
When doing soundPlayer.play() I get "Unexpectedly found nil while implicitly unwrapping an Optional value"
I have seen this problem on Stack Before and they just enable permissions on a static file. Here the file path always changes so I cannot perform their solution.
Any help is much appreciated, let me know if you need other code blocks. Thanks so much!

You define your path this way:
let pathForAudio: String = UserDefaults.standard.string(forKey: "path") ?? "There is no path for the audio"
This could result in:
A valid file path stored in UserDefaults
An invalid file path stored in UserDefaults
Nothing stored in UserDefaults, which would then cause it to be "There is no path for the audio"
Unless you get scenario #1, then your next call (let url = URL(string: pathForAudio)) will fail, returning a nil value (which is what's happening right now. Then, upon calling try AVAudioPlayer(contentsOf: url!), because you're force unwrapping with !, you'll have a crash because you have a nil value that you're telling the system isn't nil by using !
In short, you need to put a valid path into UserDefaults in order for this system to work.
I'd also do some error checking along the way. Something like:
guard let pathForAudio = UserDefaults.standard.string(forKey: "path") else {
//handle the fact that there wasn't a path
return
}
guard let url = URL(string: pathForAudio) else {
//handle the fact that a URL couldn't be made from the string (ie, invalid path
return
}
//see if the file exists
guard FileManager.default.fileExists(atPath: pathForAudio) else {
//handle no file
return
}
do {
soundPlayer = try AVAudioPlayer(contentsOf: url) //notice there's now no !
} catch {
//handle error
print(error)
}

Related

Unexpectedly found nil

I guess this is basic Swift, so I'm a bit embarrassed to ask:
In my app, I download a plist file from a server as such:
Alamofire.download(url, to: destination).response { response in
if let url = response.destinationURL {
self.holidays = NSDictionary(contentsOf: url)!
}
}
The file is a valid file, and it is succesfully dowloaded and sitting physically in my Documents folder.
However, the app crashes on
self.holidays = NSDictionary(contentsOf: url)!
saying
Fatal error: Unexpectedly found nil while unwrapping an Optional value
What gives?
Your NSDictionary is failing to initialize, so when you try to force unwrap it (with the exclamation mark) it fails and crashes.
Try something like this:
if let dictionary = NSDictionary(contentsOf: url) {
self.holidays = dictionary
}
Alternatively you can use the guard statement:
guard let dictionary = NSDictionary(contentsOf: url) else {
print("NSDictionary failed to initialise")
return
}
self.holidays = dictionary

Explicitly specified type 'NSURL?' issue while updating to Swift 3

I am having issues while updating my iOS app's code to the latest version of Swift.
I have a function:
public class func gifWithURL(gifUrl:String) -> UIImage? {
// Validate URL
guard let bundleURL:NSURL? = NSURL(string: gifUrl)
else {
print("SwiftGif: This image named \"\(gifUrl)\" does not exist")
return nil
}
// Validate data
guard let imageData = NSData(contentsOf: bundleURL! as URL) else {
print("SwiftGif: Cannot turn image named \"\(gifUrl)\" into NSData")
return nil
}
return gifWithData(data: imageData)
}
And am getting a warning on the following line:
guard let bundleURL:NSURL? = NSURL(string: gifUrl)
and am getting the warning:
Explicitly specified type 'NSURL?' adds an additional level of optional to the initializer, making the optional check always succeed
Xcode allows me to fix the problem automatically. When I do this auto-fix, my code changes to:
guard let bundleURL:NSURL NSURL(string: gifUrl)
Which is obviously not the correct syntax.
I am unsure what I need to add/remove to get my code fully up to date with Swift 3 standards and working.
NSURL(string:) will return optional NSURL? instance and you are already optionally wrapping it with guard so remove the : NSURL? because you are setting it again optional instead of non-optional also, in Swift 3 use native URL and Data instead of NSURL and NSData. The whole code would be like.
guard let bundleURL = URL(string: gifUrl), let imageData = try? Data(contentsOf: bundleURL) else {
print("SwiftGif: This image named \"\(gifUrl)\" does not exist")
return nil
}
//Access the imageData here
Note: Data(contentsOf:) will throws exception so you need to catch it using do try catch block.
You are doing it too complicated. In Swift 3, we don't use NSURL. It's just URL:
guard let bundleURL = URL(string: gifUrl) else {
print("SwiftGif: This image named \"\(gifUrl)\" does not exist")
return nil
}
Then you can also get rid of your dangerous force-cast:
guard let imageData = NSData(contentsOf: bundleURL) else {
print("SwiftGif: Cannot turn image named \"\(gifUrl)\" into NSData")
return nil
}

Can't Use String Variable in NSURL?

I have a variable copiedURL which contains a URL string, I am trying to use that string variable to display an image programmatically
let url = NSURL(string: copiedURL)
let data = NSData(contentsOfURL: url!)
let image2 = UIImage(data: data!)
When I build and run I get a EXC_BAD_INSTRUCTION error fatal error: unexpectedly found nil while unwrapping an Optional value
I am certain that copiedURL has a value because I used print() to debug and everything printed just fine.
Also, I also tried:
let url = NSURL(string: "\(copiedURL)")
but that didn't solve it.
NSURL(string:) is a failable initializer. In the case that the URL isn't valid, it will not initialize a new NSURL instance, but will instead return nil.
Check that your copiedURL is a valid URL.

Parse Video Upload - Fatal error: unexpectedly found nil while unwrapping an Optional Value

I am trying to upload a video to Parse
If I just try to upload the video like so:
let videoData = NSData(contentsOfURL: url)
let videoFile = PFFile(name: "video.mov", data: videoData)
videoUploadObject["Video"] = videoFile
I will receive the error. I tried to remove this by running something like the following.
Main.sharedMain.userVideoOutputURL
returns:
file:///private/var/mobile/Containers/Data/Application/3B78A154-4340-432B-817A-2857EBA8064A/tmp/video.mov
Here is my full code:
let url = Main.sharedMain.userVideoOutputURL!
if let videoData = NSData(contentsOfURL: url) {
let videoFile = PFFile(name: "video.mov", data: videoData)
videoUploadObject["Video"] = videoFile
print("Video File \(videoFile)")
} else {
print("Else")
}
Else is always printed? What can I do to fix this? Thank you!
The URL looks fine (iOS doesn't use "/User/blah/blah/blah" for applicaion storage).
My first thought would be to check the data is writing correctly. NSData has a "writeToFile: options:" method that returns a bool. This will return false if writing has failed, and also throw an error which should give you some extra information.
let url = <YOUR_URL>
do {
// put your options in here
try data.writeToURL(url, options: NSDataWritingOptions.DataWritingAtomic)
} catch _ {
print(error.localizedDescription)
}
If writing has succeeded, then you'll want to try loading the data using "contentsWithUrl: options:". This also throws an error if it fails, and so using the "localisedDescription" property of the thrown error object you should be able to get to the bottom of why it isn't loading.
let url = <YOUR_URL>
var data: NSData? = nil
do {
// put your options in here
try data = NSData(contentsOfURL: url, options: NSDataReadingOptions.DataReadingUncached)
} catch _ {
print(error.localizedDescription)
}
Hope that helps :)

Can't get plist URL in Swift

I'm really confused on this one. There are dozens of questions around the web asking "How do I get info from my plist file in Swift?" and the same answer is posted everywhere:
let path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist")
However, this line produces always produces nil for me. I have replaced Config with other components found in the default plist file, but get nil as well.
I am trying to access my custom ProductIdentifiers Array like so:
let url = NSBundle.mainBundle().URLForResource("ProductIdentifiers", withExtension: "plist")!
var productArray = NSArray(contentsOfURL: url) as! [[String:AnyObject!]]
I get a crash stating fatal error: unexpectedly found nil while unwrapping an Optional value on productArray. I have also tried this with other default plist values in place of ProductIdentifiers.
Does anyone know why this is not working for me even though there are so many posts around of people using this successfully?
I've never heard of the OP's approach working before. Instead, you should open the Info.plist file itself, then extract values from it, like so:
Swift 3.0+
func getInfoDictionary() -> [String: AnyObject]? {
guard let infoDictPath = Bundle.main.path(forResource: "Info", ofType: "plist") else { return nil }
return NSDictionary(contentsOfFile: infoDictPath) as? [String : AnyObject]
}
let productIdentifiers = getInfoDictionary()?["ProductIdentifiers"]
Swift 2.0
func getInfoDictionary() -> NSDictionary? {
guard let infoDictPath = NSBundle.mainBundle().pathForResource("Info", ofType: "plist") else { return nil }
return NSDictionary(contentsOfFile: infoDictPath)
}
let productIdentifiers = getInfoDictionary()?["ProductIdentifiers"]
Resource represents the file name of the plist rather than its contents.
The root object of the plist is probably a dictionary.
Replace MyPlist with the real file name.
This code prints the contents of the plist
if let url = NSBundle.mainBundle().URLForResource("MyPlist", withExtension: "plist"),
root = NSDictionary(contentsOfURL: url) as? [String:AnyObject]
{
print(root)
} else {
print("Either the file does not exist or the root object is an array")
}