Unexpectedly found nil - swift

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

Related

Unexpectedly found nil while implicitly unwrapping an Optional value AVAUDIO Player 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)
}

How can i download images from multiple API urls but skip the unreachable

I am downloading images from an API (multiple urls into a CollectionView). Everything works fine until a link is not reachable and the app crashes. How can i download from the links that are reachable but skip the ones that are not?
guard let url = URL(string: self.photos[indexPath.item]) else { return cell }
cell.imageView.image = nil
DispatchQueue.global().async {
guard let image = UIImage(data: try! Data(contentsOf: url)) else { return }
let dataCompress = image.compress(to: 1000)
if let image = UIImage(data: dataCompress) {
DispatchQueue.main.async {
cell.imageView.image = image
self.photos.append(image)
}
}
}
return cell
}
"Fatal error: 'try!' expression unexpectedly raised an error: Error Domain=NSCocoaErrorDomain Code=256 "The file “665x10002.jpg” couldn’t be opened." UserInfo={NSURL=https://"*************}
Current code crashes when a link happens to be unreachable. Any help is appreciated.
As already mentioned, you should not be using try!.
You should never be using Data(contentsOf:) to fetch data from a remote server. This is explicitly mentioned in the documentation for that initializer.
Instead, you should use
URLSession.shared.dataTask(with: url) { data, response, error in
// process the data or handle the error
}
guard let image = UIImage(data: try? Data(contentsOf: url)) else { return }
The crash is occurring because you're using ! to force unwrap your try statement. Force unwrapping is dangerous (for this reason) and should only be used when you're certain that the information will be there, otherwise the app will crash. Replace ! with ?, as above, to gracefully return when the contents of the URL is not available.

do - try - catch code doesnt try or catch. just do's

thanks for any help upfront.
url session works perfect with connection, it prints the error as nil. but without it it prints the .localizedDescription just fine and shows me the right error, but then continues to do the do{ try } and crashes with this error in the try line:
Thread 6: Fatal error: Unexpectedly found nil while unwrapping an
Optional value
now I am not even sure if this has anything to do with the errorhandling. thanks for any help with understanding whats going on or just solving the problem!
func getData(completion: (() -> ())?) {
let urlString = URL(string: "https://api.coinmarketcap.com/v1/ticker/")
URLSession.shared.dataTask(with: urlString!, completionHandler: { (data, response , error) in
print("before entering do-try-catch", error?.localizedDescription)
do {
//create Dictionary
print("downloading content")
self.coinData = try JSONSerialization.jsonObject(with: data!) as! [[String:Any]]
//set connection status
self.connection = true
//update tableView
DispatchQueue.main.async {
completion?()
}
} catch {
print("catch", error.localizedDescription)
//set connection status
self.connection = false
//update tableView
DispatchQueue.main.async {
completion?()
}
}
}).resume()
}
Thread 6: Fatal error: Unexpectedly found nil while unwrapping an Optional value is a common problem for beginners.
You try to work with data that is not there.
So for example in your code you force to execute try JSONSerialization.jsonObject(with: data!)
When data is nil the code will crash.
The same at the beginning URLSession.shared.dataTask(with: urlString!, completionHandler: { (data, response, error) {}
When urlString is not a valid URL the code will be crash. (In this case the url seems to be valid).
For more information have a look here:
https://stackoverflow.com/a/24034551/4420355
Try the following snipped it should work
if let data = data {
self.coinData = try JSONSerialization.jsonObject(with: data) as? [[String:Any]]
//... work with coinData
}
Reason why it is crashing is because data is Optional and it should be nil or has some value. On line
self.coinData = try JSONSerialization.jsonObject(with: data!) as! [[String:Any]]
Compiler thinks:
Let's take a look and unwrap this Optianal variable. But it's nil, there is "nothing"! So what should I unwrap? Let's crash and throw Fatal Error message.
How to easily avoid this with Optional binding:
if let data = data {
....do something with data
} else {
...print error message
}
For more information take look at this brilliant answer.
https://stackoverflow.com/a/32170457/3046686

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")
}