How do I get the error message in Swift 2.0? - ios

I used this method very much in Swift 1.2: NSURLConnection.sendSynchronousRequest(:_:_:_) but this is apparently deprecated in iOS9. It still works however but now it uses the new Swift 2.0 Error Handling and I don't know how I will get the error message if it fails, ex. if time runs out.
I know I have to put it into a do-catch and then say try before the metho but I dont know how to catch the error message.
do {
let data = try NSURLConnection.sendSynchronousRequest(request, returningResponse: nil)
return data
}
catch _ {
return nil
}
Before I used NSError and then its description property, but now I have no clue.

Use automatic error variable, and you can cast it to NSError if you wish:
catch {
let nsError = error as NSError
print(nsError.localizedDescription)
}

You can now throw any object inheriting ErrorType, and provide custom handling in the catch sentence. You can also cast the error to NSError to access localizedDescription for handling third party errors.
Casting an enum ErrorType will produce a NSError with domain equal to the enum name, code equal to the enum value and an auto-generated localizedDescription with the following format:
The operation couldn’t be completed. (DOMAIN error CODE.)
For example, the following code:
enum AwfulError: ErrorType {
case Bad
case Worse
case Terrible
}
func throwingFunction() throws {
throw AwfulError.Worse
}
do {
try throwingFunction()
}
catch AwfulError.Bad {
print("Bad error")
}
catch let error as NSError {
print(error.localizedDescription)
}
Will print
The operation couldn’t be completed. (AwfulError error 1.)

Despite the question title specifying Swift 2, this answer is for Swift 3.
As #redent84 points out, since Swift 2 an Error object may be a home-made one. Here's a method I wrote to analyze and print the default error object available in a "catch" statement that doesn't specify any specific error type:
// Method to print an unknown Error type object to the system output.
static func printCaughtError(_ unknownError : Error) {
let objectDescription = String(describing: unknownError)
let localizedDescription = unknownError.localizedDescription
if localizedDescription != "" {
if localizedDescription.contains(objectDescription) {
print(localizedDescription)
return
}
if !objectDescription.contains(localizedDescription) {
print(objectDescription + ": " + localizedDescription)
return
}
}
print(objectDescription)
}
Then you can call it like this:
catch {
printCaughtError(error)
}

How to get the error message that is inside userInfo:
let errorMessage = (error as NSError).userInfo["message"] as? String

Related

Firebase: How To Access error object in iOS callback [duplicate]

I used this method very much in Swift 1.2: NSURLConnection.sendSynchronousRequest(:_:_:_) but this is apparently deprecated in iOS9. It still works however but now it uses the new Swift 2.0 Error Handling and I don't know how I will get the error message if it fails, ex. if time runs out.
I know I have to put it into a do-catch and then say try before the metho but I dont know how to catch the error message.
do {
let data = try NSURLConnection.sendSynchronousRequest(request, returningResponse: nil)
return data
}
catch _ {
return nil
}
Before I used NSError and then its description property, but now I have no clue.
Use automatic error variable, and you can cast it to NSError if you wish:
catch {
let nsError = error as NSError
print(nsError.localizedDescription)
}
You can now throw any object inheriting ErrorType, and provide custom handling in the catch sentence. You can also cast the error to NSError to access localizedDescription for handling third party errors.
Casting an enum ErrorType will produce a NSError with domain equal to the enum name, code equal to the enum value and an auto-generated localizedDescription with the following format:
The operation couldn’t be completed. (DOMAIN error CODE.)
For example, the following code:
enum AwfulError: ErrorType {
case Bad
case Worse
case Terrible
}
func throwingFunction() throws {
throw AwfulError.Worse
}
do {
try throwingFunction()
}
catch AwfulError.Bad {
print("Bad error")
}
catch let error as NSError {
print(error.localizedDescription)
}
Will print
The operation couldn’t be completed. (AwfulError error 1.)
Despite the question title specifying Swift 2, this answer is for Swift 3.
As #redent84 points out, since Swift 2 an Error object may be a home-made one. Here's a method I wrote to analyze and print the default error object available in a "catch" statement that doesn't specify any specific error type:
// Method to print an unknown Error type object to the system output.
static func printCaughtError(_ unknownError : Error) {
let objectDescription = String(describing: unknownError)
let localizedDescription = unknownError.localizedDescription
if localizedDescription != "" {
if localizedDescription.contains(objectDescription) {
print(localizedDescription)
return
}
if !objectDescription.contains(localizedDescription) {
print(objectDescription + ": " + localizedDescription)
return
}
}
print(objectDescription)
}
Then you can call it like this:
catch {
printCaughtError(error)
}
How to get the error message that is inside userInfo:
let errorMessage = (error as NSError).userInfo["message"] as? String

Swift 2.1 - Error Handling - Multiple Catch is not compiled

I have a function assignName(name:) which throws an error. When that function is called from a do block with multiple catch, It shows the error as:
Errors thrown from here are not handled because the enclosing catch is not exhaustive
My Code is:
enum PersonError: ErrorType {
case IsNotAPerson
case IsNotAGoodPerson
case IsNotAValidPerson
}
func assignName(name: String?) throws {
guard name != nil else {
throw PersonError.IsNotAPerson
}
personName = name
}
func catchingSpecificError() {
do {
try assignName(nil) // Compiler Error displays at this line.
}catch PersonError.IsNotAPerson {
print("Propagated error is caught in catch on case .NotAPerson")
}
}
Thanks in Advance!
You need to include a default catch block (much like when using a switch case) to make your error handling exhaustive; in case the error thrown is not one of the ones you specify.
func catchingSpecificError() {
do {
try assignName(nil) // Compiler Error displays at this line.
}catch PersonError.IsNotAPerson {
print("Propagated error is caught in catch on case .NotAPerson")
}catch {
print("default..")
}
}
Slightly off-topic, but I assume personName = name refers to a class property personName that we cannot see in your example above.
With the default catch block added, you mention in the comments below that function catchingSpecificError() does not cast the error you expect; or rather, the default catch block catches your error.
Now, since I don't know the context of your code, I cannot infer what is actually going wrong in your case. I'll post a working example for your below where---in the context of this question---the throw and catch work as expected. Note however that your use of the guard block is somewhat out of by convention. Usually you make use of guard just like if let blocks, i.e., guard let name = name else { .., which will enter the guard block if name contains nil.
Anyway, consider the following fully working example:
enum PersonError: ErrorType {
case IsNotAPerson
case IsNotAGoodPerson
case IsNotAValidPerson
}
class Person {
var personName : String? = ""
func assignName(name: String?) throws {
guard name != nil else {
throw PersonError.IsNotAPerson
}
personName = name
}
func catchingSpecificError() {
do {
try assignName(nil)
}catch PersonError.IsNotAPerson {
print("Propagated error is caught in catch on case .NotAPerson")
}catch {
print("default..")
}
}
}
var myPerson = Person()
var myName : String? = nil
myPerson.catchingSpecificError()
/* Prints: "Propagated error is caught in catch on case .NotAPerson" */
As expected, we catch PersonError.IsNotAPerson thrown by function assignName. Hopefully you can make use of this example your get your own code (the parts that you haven't shown us in your question) working.

Parse iOS - How to capture the findObjects() error being thrown?

I am coding in Swift and attempting to use the findObjects() function for the Parse iOS SDK. However, I can't seem to figure out what type of error is being thrown by Parse if this function call fails. I'm a novice in Swift so that may be my issue. I attempt to call the function in a do->catch block and use the try keyword on the function call however I'm not sure what to catch. I can catch the error using the _ but I would like to grab the description from the error. Thanks!
P.S. I don't want to use the findObjectsInBackground() method.
do {
let object = try query.getFirstObject()
// do something with the object
} catch _ {
// this is where I would like to print out the error description
}
In Obj-C, which I assume will be similar, I print out the error.userInfo[#"error"] parameter of the NSError that is returned.
All you need is print(error). An example here:
func getReferenceNumberAsStringSync() -> String? {
let query = PFQuery(className: "PropertyCount")
do {
let object = try query.getFirstObject()
if let referenceNumber = object["count"] as? Int {
return String(referenceNumber)
}
} catch {
print(error)
}
return nil
}

handling error using xcode 7.0 beta in asynchronous block

I am trying to validate different errors while downloading text files from AWS S3, and with the next piece of code:
... above here function receiving String parameters ruta, archivo, archivoLocal
let directorioURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first! as NSURL
let archivoURL = directorioURL.URLByAppendingPathComponent("b\(archivoLocal)")
let downloadRequest = AWSS3TransferManagerDownloadRequest()
downloadRequest.bucket = ruta
downloadRequest.key = archivo
downloadRequest.downloadingFileURL = archivoURL
let transferManager = AWSS3TransferManager.defaultS3TransferManager()
let task = BFTask()
let executor = BFExecutor.mainThreadExecutor()
transferManager.download(downloadRequest).continueWithExecutor(executor, withBlock: { (task) -> AnyObject! in
if task.error != nil {
if task.error.domain == AWSS3TransferManagerErrorDomain {
self.processDomainErrorType(AWSS3TransferManagerErrorType(rawValue: task.error.code))
} else {
self.processError(task.error)
}
} else if task.result != nil {
do {
let mytext = try String(contentsOfURL: archivoURL, encoding: NSUTF8StringEncoding)
self.processResult(mytext)
} catch let urlerror as? NSError {
self.processError(urlerror)
}
}
...
I am getting the error:
Invalid conversion from throwing function of type '(_) throws -> AnyObject!' to non-throwing function type '#convention(block) (BFTask!) -> AnyObject!'
I obtained the "do { try } catch" syntax from https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html#//apple_ref/doc/uid/TP40014216-CH7-ID10
I can remove the error by replacing the catch clause with:
} catch _ {
self.processError(NSError(domain: "String-ContentsOfURL Error", code: 100, userInfo: nil))
}
Of course this way I will never know the real cause why ContentsOfURL could be failing.
All I can figure out why this error happens is because this syntax is valid only for OS X apps and for iOS the error handling guide at
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html#//apple_ref/doc/uid/TP40014097-CH42
allows only the second syntax unless you own the object throwing the errors from an enum structure of ErrorType type, which is not the case since I want to catch the NSError from String object, contentsOfURL function.
I hope someone could guide me through this, maybe being XCode 7 a beta, the catch syntax is still incomplete or maybe I should not matter about the reason why this function fails, but I think it is important to determine what is making this function fail and if it could be traced and fixed before reaching the do-try-catch clause.
Additionally to the above error, I am getting a warning in the task variable assignation line to BFTask() saying that "Initialization of immutable value 'task' was never used". I think this is a bug with this beta version that it doesn't include the pattern to acknowledge that the variable task is being used in the asynchronous block. I'd appreciate a lot some confirmation about this and if I just need to ignore it.
By the way, the only reason I am using XCode 7 beta is because my client wants to evaluate the app before acquiring their apple membership.
Apple replaced NSError with ErrorType in Swift 2.
Replace your own explicit usage of NSError with ErrorType and you don't get this type of compiler errors.

Proper Error handling in Swift

Hey stackoverflow members,
I work really hard on getting better on Swift, now I have a trivial problem. I'm a former C# developer so Error Handling until now was try {}... catch {}... Message... Done!
Now I'm developing an App which uses some JSON APIs. It's all working, downloading JSON Data, pack them into my Objects but there is one problem. The proper Error Handling..
I have the following code to download & parse JSON:
//Download & Parse JSON
func getJSON(urlToRequest: String) -> NSDictionary {
var url: NSURL = NSURL(string: urlToRequest)
var jsonRequest: NSURLRequest = NSURLRequest(URL: url)
var jsonResponse: AutoreleasingUnsafePointer<NSURLResponse?> = nil
var error: NSError?
var dataValue: NSData = NSURLConnection.sendSynchronousRequest(jsonRequest, returningResponse: jsonResponse, error:&error)
if error.description.isEmpty {
var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataValue, options: NSJSONReadingOptions.MutableContainers, error: &error) as NSDictionary
if error.description.isEmpty {
return jsonResult
}
else {
return NSDictionary(object: "Error: Something with parsing went wrong :(", forKey: "error")
}
}
else {
return NSDictionary(object: "Error: There was an error with your connection :(", forKey: "error")
}
}
The error part is just temporary, the problem is my ViewController just calls one function to get the whole data for the week (days, matchups and so on)
I call it this way:
var rWrapper = RiotWrapper()
let lcsWeek: Week = rWrapper.getWeek("2014-07-07")
My getWeek method calls 3-4 functions which all parse JSON data in relation to the previous responses.
Ok, long story short question: I want to abort all Tasks if JSON or HTTP fails and fill my TableView just with an error message, how can I achieve this?
Something like: if error occurred -> Stop whatever you are doing -> return for example a null erm.. nil for week -> print error
Can someone help me? If someone have some lecture according this topic it will be fine also :D
Thanks in advance!
Btw: sorry for my "bad" english
All of your JSON parsing methods including getWeek should return a tuple with an optional return value and an error. If at any point you get an error in one of your methods from the JSON parsing, just immediately return the error with nil for the return value. Each method up the chain should check for an error from the previous methods and immediately return the error if it finds one:
func getWeek(string : String) -> (Week?, NSError) {
let (result, error) = self.otherMethod()
if error {
return (nil, error)
}
// continue happily ...
}
I would suggest having your function return an optional. It is easy to test and functions can be chained and shortcut.
func getWeek(string : String) -> Week? {
...
if error {
return nil
}
}
This can be quickly evaluated like this:
if let week = getWeek("2014-07-07") {
// handle success case
} else {
// handle nil
}
and check here for how to string together a number of functions that return optional:
https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html

Resources