Swift 3 error handling and variable accessibility - ios

I have a question on how to use the new error handling in Swift.
I'm reading contents of a file into a data object:
var overallData: Data?
//load file contents into data object
let dataFileURL = NSURL(string: fileName)
do {
overallData = try Data(contentsOf: dataFileURL as! URL)
} catch {
print("\(error)")
}
The problem is that I always encounter this error message:
fatal error: unexpectedly found nil while unwrapping an Optional value
The problem is that the overallData object is set as nil. But if I don't define a data variable outside the do-catch,
let dataFileURL = NSURL(string: fileName)
do {
overallData = try Data(contentsOf: dataFileURL as! URL)
} catch {
print("\(error)")
}
Later on, I can't use the overallData object because the system keeps telling me it's a variable not defined yet. So it looks like new variables defined in the do-catch loop can only be locally accessed inside the loop.
Do you know how to solve this problem? I do need to use the overallData object elsewhere.

The following answer assumes your error is with the line:
overallData = try Data(contentsOf: dataFileURL as! URL)
If you are getting the "fatal error" on another line, please update your question.
Your error has nothing to do with the do/catch/try.
Your problem is the force unwrapping of dataFileURL which is nil.
Your problem is this line:
let dataFileURL = NSURL(string: fileName)
This is returning nil because fileName isn't a valid URL.
Assuming fileName is a path to a local file, you need to do:
let dataFileURL = URL(fileURLWithPath: fileName)
Also note the use of URL instead of NSURL. There is no sense in using NSURL in Swift 3.

Related

Found nil value in dictionary when it isn't nil

I want to create URL from string in dictionary, but when I initialize it, the guard statement goes to else statement, because values["Image"] is nil and return the function. Here is a piece of my code
guard let imageURLInDatabase = URL(string: values["Image"]!) else { return }
let data = NSData(contentsOf: imageURLInDatabase)
I have create afew breakpoint in my code:
And here is my console log at this breakpoint:
What did I miss?
P.S
I tried to do it like:
let imageURLInDatabase = URL(string: values["Image"]!)
but I got error message unexpectedly found nil while unwrapping an optional value
Edit 1:
I tried to do it like
guard let imageString = values["Image"] else{return}
guard let imageURLInDatabase = URL(string: imageString) else{
return}
let data = NSData(contentsOf: imageURLInDatabase)
And set breakpoints:
So values["Image"] can't be nil
Edit 2:
This is what is in values["Image"]:
some : "https://firebasestorage.googleapis.com/v0/b/blackjack-ef580.appspot.com/o/profiles_images%2FdwMGR8sKMvYauf6uQDtyop18cwy1.jpg?alt=media&token=5df48794-d3fd-4e5c-a72c-9928a8a43c4e\""
The problem is the extra quotation mark at the end of the URL string. Try this:
let s = "https://firebasestorage.googleapis.com/v0/b/blackjack-ef580.appspot.com/o/profiles_images%2FdwMGR8sKMvYauf6uQDtyop18cwy1.jpg?alt=media&token=5df48794-d3fd-4e5c-a72c-9928a8a43c4e\""
let url = URL(string:s)
You'll get nil.
The problem isn't that values["Image"] is nil. The problem is that values["Image"] isn't a value URL string.
Make sure you properly encode spaces and other special characters in the URL.
And as a side note, do not use NSData, use Data.
According to your trace, the problem isn't that value["Image"] is nil. If that were the case, you would have crashed rather than called return. Your problem is that whatever the value of value["Image"], it is not a valid URL. Without seeing the value, it's difficult to know exactly what is wrong with it, but it is malformed in some way.
This is because the dictionary values does not contains the key Image. So values['Image'] will return nil, and force unwrapping a nil will crash the app.
Try using guard else statements to unwrap it
guard let imageValue = values["Image"] as? String else {
//imageValue is nil here, handle accordingly
return
}
guard let imageURLInDatabase = URL(string: imageValue) else {
//imageURLInDatabase is nil here, handle accordingly
return
}
let data = NSData(contentsOf: imageURLInDatabase)
Edit 1:
With your updated question, and the breakpoint image, values["Image"] is not null, imageURLInDatabase is nil due to which it goes to else case.
The reason could be that values["Image"] might not be returning a valid url, due to which URL(string: ..) fails.
Edit 2 :
Check the string url you just shared
"https://firebasestorage.googleapis.com/v0/b/blackjack-ef580.appspot.com/o/profiles_images%2FdwMGR8sKMvYauf6uQDtyop18cwy1.jpg?alt=media&token=5df48794-d3fd-4e5c-a72c-9928a8a43c4e\""
has an extra quote in the end!

Swift3 : unexpectedly found nil while unwrapping an Optional value

I ve just upgrade from Swift 2 to Swift 3, and i m facing a new challenge...
I have a player which run perfectly before, but now i have this following issue : "unexpectedly found nil while unwrapping an Optional value"
Here is my code :
print(audioselectionne)
let alertSound = URL(fileURLWithPath: Bundle.main.path(forResource: audioselectionne as String, ofType: "mp3")!)
I ve got : Optional("tiesto") and the crash...
I really dont understand where is the issue...
Thanks for the help.
You should unwrap the optional, perhaps with optional binding.
BTW, you shouldn't be use path strings at all anymore. Just use the URL directly, e.g.
guard let resource = audioselectionne, let alertSound = Bundle.main.url(forResource: resource, withExtension: "mp3") else {
// handle file not found here
return
}
// use alertSound here
I think the Bundle.main.path method returns an optional String. When that’s nil (because the resource was not found), force-unwrapping it causes your error. If you want to handle it correctly, you have to check for the nil:
guard let path = Bundle.main.path(…) else {
// resource not found, handle error
}
// now `path` is guaranteed to be non-nil
let alertSound = URL(fileURLWithPath: path)

UIImage Download Returning nil and Crashing App (Swift)

I have an image url string:
var remoteImage: String = "http://server.com/wall-e.jpg"
I then construct a UIImage to download on a separate thread using Grand Central Dispatch with remoteImage as the NSURL string parameter:
let getImage = UIImage(data: NSData(contentsOfURL: NSURL(string: remoteImage)!)!)
When it is finished and I return back to the main thread, I have it save internally:
UIImageJPEGRepresentation(getImage, 1.0).writeToFile(imagePath, atomically: true)
On Wi-fi and LTE it downloads fine, but when testing edge cases such as on an Edge network (no pun intended), I inconsistently get the error:
fatal error: unexpectedly found nil while unwrapping an Optional value
Now I thought I would be safe by making sure that it wasn't nil by adding in:
if getImage != nil { ... }
But it didn't seem to make a difference. It still gets the error and highlights the let getImage as written above. What am I doing wrong here? Should I be checking nil in a different manner or method?
I would recommend you to use AsyncRequest to fetch and download the image and saved it locally.
As you didn't posted any of code of your problem.
So i am posting a sample working for me.
Sample for downloading and saving image locally
var url = NSURL(string : "http://freedwallpaper.com/wp-content/uploads/2014/09/Tattoo-Girl.jpg")
let urlrequest = NSURLRequest(URL: url!)
NSURLConnection.sendAsynchronousRequest(urlrequest, queue: NSOperationQueue.mainQueue(), completionHandler: {
response ,data , error in
if error != nil
{
println("error occurs")
}
else
{
let image = UIImage(data: data)
/* Storing image locally */
var documentsDirectory:String?
var paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
println(paths)
if paths.count > 0{
documentsDirectory = paths[0] as? String
var savePath = documentsDirectory! + "/bach.jpg"
NSFileManager.defaultManager().createFileAtPath(savePath, contents: data, attributes: nil)
self.bach.image = UIImage(named: savePath)
}
}
})
}
The error, does, in fact lie on the line:
let getImage = UIImage(data: NSData(contentsOfURL: NSURL(string: remoteImage)!)!)
The reason is that it's not the UIImage that is initially returning nil, it is probably NSData returning nil. You could check if NSData is returning nil, and then create the UIImage object instead.
EDIT: What the particular line of code is doing is it is assuming that NSData is always returning a non-nil value, which may not be true when you are not connected. When you're not connected, it gets a nil value, which you are trying to say will never be a nil value using the exclamation mark (!).
I suggest you read further on how Swift works. For this particular example, take a look at what the exclamation marks actually mean in Swift: What does an exclamation mark mean in the Swift language?

Check if url image exist

I'm trying to check if a url image exist using a if statement. However when trying to test it by wrong image url it keep returning:
fatal error: unexpectedly found nil while unwrapping an Optional value.
code:
var httpUrl = subJson["image_url"].stringValue
let url = NSURL(string: httpUrl)
let data = NSData(contentsOfURL: url!)
if UIImage(data: data!) != nil {
}
You can do it this way:
var httpUrl = subJson["image_url"].stringValue
if let data = NSData(contentsOfURL: url) {
//assign your image here
}
Other answers are telling you to unwrap the optional, but really the issue is that you are force-unwrapping the optional with !, despite it being nil.
When you write something! what you are saying is “something might be nil, but if it is, I want my program to crash”.
The reason a call might return nil is if the result is not valid – for example, if you try to fetch a key from a dictionary that isn’t there, or that a URL doesn’t point to a valid downloadable image.
You can combine the check for nil with an if statement that unwraps the optional and returns a non-optional value so long as the value wasn’t nil. You can also chain them together, so if you need to unwrap a value, then pass it into a call that also returns an optional, you can do it all in one if statement:
if let httpUrl = subJson["image_url"].string,
url = NSURL(string: httpUrl),
data = NSData(contentsOfURL: url),
image = UIImage(data: data)
{
// use image value
}
else {
// log some error
}
Note, on the first line, the call is to .string rather than .stringValue – .string also returns an optional with nil if the value isn’t present.
Of course, combining all these unwraps together means you can’t tell which one failed, so you may want to break them out into separate statements instead.
This code is tested and successful: if image url not exists no crash.
let url: NSURL = NSURL(string: "http://www.example.com/images/image.png")!
do {
let imgData = try NSData(contentsOfURL: url, options: NSDataReadingOptions())
ImageView?.image = UIImage(data: imgData)
} catch {
print(error)
}
You have to unwrap the optional like this:
if let image = data {
// use image here
} else {
// the data is nil
}

OSStatus error 2003334207 when using AVAudioPlayer

I am trying to play an MP3 file (works when played via VLC/iTunes) when a button is pressed. Here is my code:
var audioPlayer: AVAudioPlayer!
#IBAction func playEpisode(sender: AnyObject) {
println("now playing")
let indexPath = NSIndexPath(forRow: sender.tag, inSection: 0)
let data: CDEpisode = fetchedResultsController.objectAtIndexPath(indexPath!) as! CDEpisode
var err: NSError?
let url = NSURL(string: data.localPath)
println("The url is \(url)")
audioPlayer = AVAudioPlayer(contentsOfURL: url, error: &err)
if audioPlayer == nil {
if let e = err {
println(e.localizedDescription)
}
}
audioPlayer.delegate = self
audioPlayer.prepareToPlay()
audioPlayer.play()
}
Here is the log:
now playing
The url is Optional(file:///var/mobile/Containers/Data/Application/4747A71E-A63F-4EFC-B2DF-8B361361080B/Documents/serial-s01-e12.mp3)
The operation couldn’t be completed. (OSStatus error 2003334207.)
fatal error: unexpectedly found nil while unwrapping an Optional value
The EXC_BREAKPOINT happens on the audioPlayer.delegate = self.
Other threads on StackoOverflow do not help. Any ideas?
Thanks
Edit: I have tried passing a localURL to contentsOfURL (instead of a CDEpisode object) and it still fails.
This is probably caused by trying to load a file that doesn't exist. If that helps someone adding the call to url.checkResourceIsReachable() will log more descriptive message.
Example code:
do {
let url = URL(fileURLWithPath: dbObject.path)
let isReachable = try url.checkResourceIsReachable()
// ... you can set breaking points after that line, and if you stopped at them it means file exist.
} catch let e {
print("couldnt load file \(e.localizedDescription)")
}
It looks like your trying to unwrap a variable that has a nil value. You should safely unwrap your variables to prevent this.
if let data: CDEpisode = fetchedResultsController.objectAtIndexPath(indexPath!) as! CDEpisode
{
var err: NSError?
let url = NSURL(string: data.localPath)
println("The url is \(url)")
//rest of code
}
You will still need to figure out why it is returning nil but this is a safer way to unwrap variables and prevent crashing as there would need to be more context to resolve that issue.
Some questions to look into:
Are you sure the fetchedResultsController is returning an object at
all?
Are you sure it is of CDEpisode?
try this one
var player: AVAudioPlayer = AVAudioPlayer()
#IBAction func playX(_ sender: Any) {
let urlstring = "https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3"
let url = URL(string: urlstring)
let data = try! Data(contentsOf: url!)
player = try! AVAudioPlayer(data: data)
player.prepareToPlay()
player.volume = 1.0
player.play()
}
You're checking if audioPlayer is nil but then you go on to use it as if it wasn't anyway. You probably want something like:
if audioPlayer == nil {
if let e = err {
println(e.localizedDescription)
}
} else {
audioPlayer.delegate = self
audioPlayer.prepareToPlay()
audioPlayer.play()
}
And do something to actually handle the error case rather than just printing the error.
In my case I was having the same issue and I found out that I needed to set this before start recording
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord)
Hope it helps anyone
I also got this problem, after checking up the audio file url, found that it is stored in Cache directory. so audio player probably couldn't find audio file according to your "url".
please ensure, the url path is under Document directory.
As others have said, the audio player couldn't find the file.
This helped me: Document directory path change when rebuild application
Basically, you cannot load files with an absolute reference, as the sandbox environment regenerates the absolute file url each time. So you will need to add a small bit of code (see above) to get the correct urls to use.

Resources