I'm trying to achieve something like this:
try {
num1 = 0;
num2 = 62 / num1;
num3 = num3/2;
}
catch (ArithmeticException e) {
/* This block will only execute if any Arithmetic exception
* occurs in try block
*/
}
But in Swift I have to use:
do {
let sandwich = try makeMeSandwich(kitchen)
let sandwich2 = try makeMeSandwich(kitchen2)
try abc(kitchen2) // no return type
print("i eat it \(sandwich)")
} catch {
print("Not me error")
}
I have to specify try for every check. Is there something I can do just like in Java for the whole method?
If no return type method like
try abc(kitchen2)
it shows me the below warning:
No calls to throwing functions occur within 'try' expression
and in a catch block:
'catch' block is unreachable because no errors are thrown in 'do' block
Related
I have a function that executes an async task. Sometimes that task fails and throws an error. I'm having trouble catching that error from the calling function. The playground below captures the essence of the trouble I'm having.
import UIKit
Task {
var newNum: Double = 99.9
do {
newNum = try await getMyNumber()
print("newNum within do: \(newNum)")
} catch MyErrors.BeingStupid { //never gets caught
print("caught being stupid")
} catch MyErrors.JustBecause { //does get caught if throw is uncommented
print("caught just because")
}
print("newNum outside of do \(newNum)")
}
print("done with main")
func getMyNumber() async throws -> Double {
let retNum:Double = 0
Task{
sleep(5)
let myNum: Double = Double.random(in: (0...10))
if myNum > 9 {
print("greater than 9")
} else {
print("less than 9 -- should throw")
throw MyErrors.BeingStupid // error doesn't get thrown? HOW DO I CATCH THIS?
}
}
// throw MyErrors.JustBecause // this *does* get caught if uncommented
return retNum //function always returns
}
enum MyErrors: Error {
case BeingStupid, JustBecause
}
How do I catch the error being thrown at the line commented "HOW DO I CATCH THIS" back in the calling function?
Task is for unstructured concurrency. If the intent is to simulate an asynchronous task, I would advise remaining within structured concurrency. So, use Task.sleep(nanoseconds:) instead of sleep() and eliminate the Task within getMyNumber:
func getMyNumber() async throws -> Double {
try await Task.sleep(nanoseconds: 5 * NSEC_PER_SEC) // better simulation of some asynchronous process
let myNum = Double.random(in: 0...10)
if myNum > 9 {
print("greater than 9")
} else {
print("less than 9 -- should throw")
throw MyErrors.beingStupid
}
return myNum
}
enum MyErrors: Error {
case beingStupid, justBecause
}
If you stay within structured concurrency, errors that are thrown are easily caught.
For more information about the difference between structured and unstructured concurrency, see The Swift Programming Guide: Concurrency or WWDC 2021 video Explore structured concurrency in Swift
The above illustrates the standard structured concurrency pattern. If you really must use unstructured concurrency, you could try await the Task and, if it didn't throw an error, return its value, e.g.:
func getMyNumber() async throws -> Double {
let task = Task.detached {
sleep(5) // really bad idea ... never sleep ... especially never sleep on the main actor, which is why I used `Task.detached`
let myNum = Double.random(in: 0...10)
if myNum > 9 {
print("greater than 9")
} else {
print("less than 9 -- should throw")
throw MyErrors.beingStupid
}
return myNum
}
return try await task.value
}
Note, because we’re running something slow and synchronous, we want it to run on a background thread, and therefore use Task.detached.
I only include this unstructured concurrency example for the sake of completeness. You most likely will want to remain within structured concurrency. That way, you enjoy not only a more concise implementation, but also automatic propagation of cancelation, etc.
I create a set of promises which relies on the results from a function that may throw an error. I can get this to work as shown in the code below, but I don't like the double catch blocks. I'd like to use the a single promiseKit catch block. Anyone have a better solution that works?
do {
let accounts = try Account.getAccounts()
let mailboxPromises = accounts.map { self.fetchMailboxes($0) }
when(fulfilled: mailboxPromises).map { _ in
self.updateBadgeCount()
}
.catch { (error) in
}
} catch {
}
Maybe wrap Account.getAccounts() in a promise which you can then use in your promise chain?
func getAccounts() -> Promise<[Account]> {
return Promise {
do {
let accounts = try Account.getAccounts()
$0.fulfill(accounts)
} catch {
$0.reject(error)
}
}
}
UPDATE:
Below info is from the documentation at https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md so you should be able to use this pattern instead of your do/catch block.
Since promises handle thrown errors, you don't have to wrap calls to throwing functions in a do block unless you really want to handle the errors locally:
foo().then { baz in
bar(baz)
}.then { result in
try doOtherThing()
}.catch { error in
// if doOtherThing() throws, we end up here
}
I am working on a piece of code that is going to fetch an array of NSManagedObjects from CoreData. When using a do catch statement in my code it doesn't seem right to do it this way, but it is the simplest way I can write this line of code.
In any other scenario when you use the return statement you are jumping out of the current function you are in. And you can be assured that no other code in your function will execute past the return statement. I am wondering if the same applies to Swift's do catch paradigm.
class func getAll() -> [MMNotification] {
let context = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<MMNotification>(entityName: "MMNotification")
do {
return try context.fetch(fetchRequest)
}
catch {
// Will this 'catch' if the try fails,
// even if we said we are 'return'ing right before the 'try'?
return []
}
}
Here I am fetching a list of notifications stored in CoreData. In the do block you can see the line of code in question.
QUESTION
Will the catch block execute if the try fails after already stating that the function should return?
What you have should work as expected. Basically what happens is if a throw occurs at any time within a do, the catch is called and any code after the throw will not be executed.
Yes, the catch block will execute if the try in return try fails. The return will not happen.
Here's a little code to prove it to yourself. Paste it into a new playground to try it out.
import UIKit
let shouldFail = true
enum DemoError:Error {
case shouldFail
}
func failableGetter() throws -> String {
if shouldFail { throw DemoError.shouldFail }
return "Succeeded"
}
func fetchInfo() -> String {
do {
return try failableGetter()
} catch {
return "Failed"
}
}
print(fetchInfo()) // "Failed" or "Succeeded" depending on shouldFail
When shouldFail is true, the failableGetter() throws an error and the do-catch in fetchInfo() skips to the catch section before returning.
When shouldFail is false, the failableGetter() doesn't fail and fetchInfo() returns the result.
Adding to this answer. Scope matters a bit here. Code inside the do block code after a throw will NOT be executed. However, code further down outside of the scope of the do block will be executed. I made a simple playground you can run to see for yourself.
import Foundation
let error = NSError(domain: "", code: 123, userInfo: [NSLocalizedDescriptionKey: "My error"])
func functionThatAlwaysThrows() throws {
throw(error)
}
func myFunction() {
do {
try functionThatAlwaysThrows()
// This will never print
print("Continuing after throw inside do scope")
} catch let err {
print("Caught Error: \(err.localizedDescription)")
}
// This will always print
print("Continuing after throw outside do scope")
}
Output:
Caught Error: My error
Continuing after throw outside do scope
If you want more information on Error handling you can take a look at the docs
I'm migrating my code over to Swift 3 and see a bunch of the same warnings with my do/try/catch blocks. I want to check if an assignment doesn't return nil and then print something out to the console if it doesn't work. The catch block says it "is unreachable because no errors are thrown in 'do' block". I would want to catch all errors with one catch block.
let xmlString: String?
do{
//Warning for line below: "no calls to throwing function occurs within 'try' expression
try xmlString = String(contentsOfURL: accessURL, encoding: String.Encoding.utf8)
var xmlDict = XMLDictionaryParser.sharedInstance().dictionary(with: xmlString)
if let models = xmlDict?["Cygnet"] {
self.cygnets = models as! NSArray
}
//Warning for line below: "catch block is unreachable because no errors are thrown in 'do' block
} catch {
print("error getting xml string")
}
How would I write a proper try catch block that would handle assignment errors?
One way you can do is throwing your own errors on finding nil.
With having this sort of your own error:
enum MyError: Error {
case FoundNil(String)
}
You can write something like this:
do{
let xmlString = try String(contentsOf: accessURL, encoding: String.Encoding.utf8)
guard let xmlDict = XMLDictionaryParser.sharedInstance().dictionary(with: xmlString) else {
throw MyError.FoundNil("xmlDict")
}
guard let models = xmlDict["Cygnet"] as? NSArray else {
throw MyError.FoundNil("models")
}
self.cygnets = models
} catch {
print("error getting xml string: \(error)")
}
So on a button press I'm creating splitLat: [Double] from a throwing function called splitLatitude that takes currentLocation: CLLocationCoordinate2D?. I then want to use splitLat as a Label (its going to be used for other things as well but this serves the example)
#IBAction func ButtonPress() {
let splitLat = try self.splitLatitude(self.currentLocation)
LatSplitLabel.text = "\(splitLat)"
}
this gets a error "Errors thrown from here are not handled"
I resolve this by putting it in a do catch block
do{
let splitLat = try self.splitLatitude(self.currentLocation)
} catch {
print("error") //Example - Fix
}
but the when i try to set the label later on splitLat is an "unresolved identifier"
New to swift and programming in general, am i missing something basic/ do i have a mis understanding? is there a way i can use the constant from the do {} statement outside of the do statement. Tried return but that is reserved for functions.
Really appreciate any help
Thanks
You have two options (I'll assume that splitLat is String type)
do{
let splitLat = try self.splitLatitude(self.currentLocation)
//do rest of the code here
} catch {
print("error") //Example - Fix
}
second option, predeclare the variable
let splitLat : String? //you can late init let vars from swift 1.2
do{
splitLat = try self.splitLatitude(self.currentLocation)
} catch {
print("error") //Example - Fix
}
//Here splitLat is recognized
Now, some explanation of your problem.
in Swift (and many other languages) variables are only defined inside the scope they are defined
scope is defined between these brackets {/* scope code */ }
{
var x : Int
{
//Here x is defined, it is inside the parent scope
var y : Int
}
//Here Y is not defined, it is outside it's scope
}
//here X is outside the scope, undefined
A 3rd option is to use a closure:
let splitLat:String = {
do {
return try self.splitLatitude(self.currentLocation)
}
catch {
print("error") //Example - Fix
return ""
}
}()
LatSplitLabel.text = "\(splitLat)"
This is a scoping error if you want to succeed execution after the do/catch block. You must declare the variable outside of this do/catch scope in order to utilize it after the do/catch execution.
Try this:
var splitLat: <initialType> = <initialValue>
do {
let splitLat = try self.splitLatitude(self.currentLocation)
} catch {
print("error")
}
print(splitLat)
Here is a concocted example that runs in a Swift 2.2 playground:
enum Errors: ErrorType {
case SomeBadError
}
func getResult(param: String) throws -> Bool {
if param == "" {
throw Errors.SomeBadError
}
return true
}
var result = false
do {
result = try getResult("it")
} catch {
print("Some error")
}
print(result)