do try catch swift 2 - swift2

HI i am a little confused about how to transfer if_else error handling to do try catch successfully.
Here is my code.
let error : NSError?
if(managedObjectContext!.save()) {
NSNotificationCenter.defaultCenter().postNotificationName("updateUndoState", object: nil)
if error != nil {
print(error?.localizedDescription)
}
}
else {
print("abort")
abort()
}
and now i converted to swift 2.0 like this
do {
try managedObjectContext!.save()
}
catch {
NSNotificationCenter.defaultCenter().postNotificationName("updateUndoState", object: nil)
print((error as NSError).localizedDescription)
}
I am confused about where to print abort and do the abort() function
Any idea~? Thanks a lot

Rewriting your code to work the same as your original code
do {
try managedObjectContext!.save()
//this happens when save did pass
NSNotificationCenter.defaultCenter().postNotificationName("updateUndoState", object: nil)
//this error variable has nothing to do with save in your original code
if error != nil {
print(error?.localizedDescription)
}
}
catch {
//this happens when save() doesn't pass
abort()
}
what you probably want to write is the following:
do {
try managedObjectContext!.save()
//this happens when save did pass
NSNotificationCenter.defaultCenter().postNotificationName("updateUndoState", object: nil)
}
catch let saveError as NSError {
//this happens when save() doesn't pass
print(saveError.localizedDescription)
abort()
}

Everything within do {} is good, everything within catch {} is bad
do {
try managedObjectContext!.save()
NSNotificationCenter.defaultCenter().postNotificationName("updateUndoState", object: nil)
}
catch let error as NSError {
print(error.localizedDescription)
abort()
}
use either the error handling or the abort() statement

Related

How to get reason from custom error enum on Swift failure Result

In order to track server errors from a Restfull Api on an SwiftUI IOS App I am feeding the error message from NSData to the "reason" parameter of next NetworkErrors enum:
enum NetworkError: Error {
case domainError(reason:String)
case decodingError(reason:String)
case encodingError(reason:String)
}
The error reason is fed when decoding the NSURLSession response:
static func postRequest<T:Decodable, U:Codable>(_ endpoint:String, _ input:U?, completion: #escaping (Result<T,NetworkError>) -> Void) {
...
do {
let retval = try JSONDecoder().decode(T.self, from: data)
completion(.success(retval))
} catch let DecodingError.dataCorrupted(context) {
let responseData = String(data: data, encoding: String.Encoding.utf8)
completion(.failure(.decodingError(reason: responseData ?? "Data corrupted from response")))
} catch {
...
}
...
}
The error reason should be available on next code, but I'm only able to print the localizedDescription:
Button(action:{
self.postRequest(endpoint, self.value){ (result: Result<Bool,NetworkError>) in
switch result {
case .success:
print("value saved successfully")
case .failure(let error):
print("failure to save value")
print(error.localizedDescription)
}
}
}){
Image(systemName:"icloud.and.arrow.up")
}
In the failure case, we know that error is a NetworkError, so now disassemble that error with another switch:
switch error {
case .domainError(let reason): // do something
case .decodingError(let reason): // do something
case .encodingError(let reason): // do something
}

try catch not working in swift

This should be simple and obvious but try catch in swift2 frustrating me. here is my code.
#IBAction func btnAdd_TouchDown(sender: AnyObject) {
do { try AddNewNotesToList() } catch{
if(Ex.UnknownError != "")
{
Error(Ex.UnknownError)
}
}
}
func AddNewNotesToList() throws
{
var obj: TreatmentNotesDTO = TreatmentNotesDTO()
obj.therapist_id = Int(TherapistId)! // getting error here
return
}
Error:
fatal error: unexpectedly found nil while unwrapping an Optional value
Debugger should go to catch but its breaking up. I am from c# and just started swift2. Any help
I would suggest you to use guard to catch such errors:
guard let therapistID = Int(TherapistId) else {
print(TherapistId + " cannot be converted to an Int")
return
// or mark function as throws and return an error
throw NSError(domain: TherapistId + " cannot be converted to an Int", code: 0, userInfo: nil)
}
obj.therapist_id = therapistID
Note that Int(TherapistId)! doesn't throw an error with throws. It is a fatal error which stops program execution.

Extra argument 'error' in call - swift 2 [duplicate]

I'm currently developing my first iOS app using Swift 2.0 and Xcode Beta 2. It reads an external JSON and generates a list in a table view with the data. However, I'm getting a strange little error that I can't seem to fix:
Extra argument 'error' in call
Here is a snippet of my code:
let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
print("Task completed")
if(error != nil){
print(error!.localizedDescription)
}
var err: NSError?
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as? NSDictionary{
if(err != nil){
print("JSON Error \(err!.localizedDescription)")
}
if let results: NSArray = jsonResult["results"] as? NSArray{
dispatch_async(dispatch_get_main_queue(), {
self.tableData = results
self.appsTableView!.reloadData()
})
}
}
})
The error is thrown at this line:
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as? NSDictionary{
Can someone please tell me what I'm doing wrong here?
With Swift 2, the signature for NSJSONSerialization has changed, to conform to the new error handling system.
Here's an example of how to use it:
do {
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary {
print(jsonResult)
}
} catch let error as NSError {
print(error.localizedDescription)
}
With Swift 3, the name of NSJSONSerialization and its methods have changed, according to the Swift API Design Guidelines.
Here's the same example:
do {
if let jsonResult = try JSONSerialization.jsonObject(with: data, options: []) as? [String:AnyObject] {
print(jsonResult)
}
} catch let error as NSError {
print(error.localizedDescription)
}
Things have changed in Swift 2, methods that accepted an error parameter were transformed into methods that throw that error instead of returning it via an inout parameter. By looking at the Apple documentation:
HANDLING ERRORS IN SWIFT:
In Swift, this method returns a nonoptional result and is marked with the throws keyword to indicate that it throws an error in cases of failure.
You call this method in a try expression and handle any errors in the catch clauses of a do statement, as described in Error Handling in The Swift Programming Language (Swift 2.1) and Error Handling in Using Swift with Cocoa and Objective-C (Swift 2.1).
The shortest solution would be to use try? which returns nil if an error occurs:
let message = try? NSJSONSerialization.JSONObjectWithData(receivedData, options:.AllowFragments)
if let dict = message as? NSDictionary {
// ... process the data
}
If you're also interested into the error, you can use a do/catch:
do {
let message = try NSJSONSerialization.JSONObjectWithData(receivedData, options:.AllowFragments)
if let dict = message as? NSDictionary {
// ... process the data
}
} catch let error as NSError {
print("An error occurred: \(error)")
}
This has been changed in Swift 3.0.
do{
if let responseObj = try JSONSerialization.jsonObject(with: results, options: .allowFragments) as? NSDictionary{
if JSONSerialization.isValidJSONObject(responseObj){
//Do your stuff here
}
else{
//Handle error
}
}
else{
//Do your stuff here
}
}
catch let error as NSError {
print("An error occurred: \(error)") }

How to unit test throwing functions in Swift?

How to test wether a function in Swift 2.0 throws or not? How to assert that the correct ErrorType is thrown?
EDIT: Updated the code for Swift 4.1 (still valid with Swift 5.2)
Here's the latest Swift version of Fyodor Volchyok's answer who used XCTAssertThrowsError:
enum MyError: Error {
case someExpectedError
case someUnexpectedError
}
func functionThatThrows() throws {
throw MyError.someExpectedError
}
func testFunctionThatThrows() {
XCTAssertThrowsError(try functionThatThrows()) { error in
XCTAssertEqual(error as! MyError, MyError.someExpectedError)
}
}
If your Error enum has associated values, you can either have your Error enum conform to Equatable, or use the if case statement:
enum MyError: Error, Equatable {
case someExpectedError
case someUnexpectedError
case associatedValueError(value: Int)
}
func functionThatThrows() throws {
throw MyError.associatedValueError(value: 10)
}
// Equatable pattern: simplest solution if you have a simple associated value that can be tested inside 1 XCTAssertEqual
func testFunctionThatThrows() {
XCTAssertThrowsError(try functionThatThrows()) { error in
XCTAssertEqual(error as! MyError, MyError.associatedValueError(value: 10))
}
}
// if case pattern: useful if you have one or more associated values more or less complex (struct, classes...)
func testFunctionThatThrows() {
XCTAssertThrowsError(try functionThatThrows()) { error in
guard case MyError.associatedValueError(let value) = error else {
return XCTFail()
}
XCTAssertEqual(value, 10)
// if you have several values or if they require more complex tests, you can do it here
}
}
At least of Xcode 7.3 (maybe earlier) you could use built-in XCTAssertThrowsError():
XCTAssertThrowsError(try methodThatThrows())
If nothing is thrown during test you'll see something like this:
If you want to check if thrown error is of some concrete type, you could use errorHandler parameter of XCTAssertThrowsError():
enum Error: ErrorType {
case SomeExpectedError
case SomeUnexpectedError
}
func functionThatThrows() throws {
throw Error.SomeExpectedError
}
XCTAssertThrowsError(try functionThatThrows(), "some message") { (error) in
XCTAssertEqual(error as? Error, Error.SomeExpectedError)
}
Given the following functions and declarations:
enum SomeError: ErrorType {
case FifthError
case FirstError
}
func throwingFunction(x: Int) throws {
switch x {
case 1:
throw SomeError.FirstError
case 5:
throw SomeError.FifthError
default:
return
}
}
This function will throw a FifthError if 5 is given to the function and FirstError if 1 is given.
To test, that a function successfully runs the unit test could look as follows:
func testNotError() {
guard let _ = try? throwingFunction(2) else {
XCTFail("Error thrown")
return
}
}
The let _ may also be replaced by any other name, so you can further test the output.
To assert that a function throws, no matter what ErrorType the unit test could look like this:
func testError() {
if let _ = try? throwingFunction(5) {
XCTFail("No error thrown")
return
}
}
If you want to test for a specific ErrorType it's done with a do-catch-statement. This is not the best way compared to other languages.
You have to make sure that you...
return in the catch for the correct ErrorType
XCTFail() and return for all other catch
XCTFail() if no catch is executed
Given this requirements a test case could look like this:
func testFifthError() {
do {
try throwingFunction(5)
} catch SomeError.FifthError {
return
} catch {
XCTFail("Wrong error thrown")
return
}
XCTFail("No error thrown")
}
Swift 4.1 Error throwing Test for associated values
enum ParseError: Error, Equatable {
case unexpectedArgument(String)
}
func testWithNoSchemaButWithOneArgument() {
XCTAssertThrowsError(try Args(withSchema: "", andArguments: ["-x"])) { error in
XCTAssertEqual(error as? ParseError, ParseError.unexpectedArgument("Argument(s) -x unexpected."))
}
}
You can use this function:
func XCTAssertThrowsError<T, E: Error & Equatable>(
_ expression: #autoclosure () throws -> T,
error: E,
in file: StaticString = #file,
line: UInt = #line
) {
var thrownError: Error?
XCTAssertThrowsError(
try expression(),
file: file,
line: line) {
thrownError = $0
}
XCTAssertTrue(
thrownError is E,
"Unexpected error type: \(type(of: thrownError))",
file: file,
line: line
)
XCTAssertEqual(
thrownError as? E,
error,
file: file,
line: line
)
}
Example:
XCTAssertThrowsError(try funcThatThrowsSpecificError(), error: SpecificErrorEnum.someError)

Parse/Swift getObjectInBackgroundWithId query not working

I am trying to run the query to get object in background with ID but when I run the method query.getObjectInBackgroundWithId , I am getting the error message:
"Cannot invoke 'getObjectInBackgroundWithId' with an argument list of type (string, block: (PFObject!,NSError?) -> Void"
The same thing happens when I use user.signUpInBackgroundWithBlock so I'm thinking maybe Xcode updated some of the features while using 'block's and now maybe the syntax is different? Any ideas?
Here's a snippet of my code:
http://imgur.com/1CvfhbU
YES!!! Thank you!
The new sample code for getObject is:
query.getObjectInBackgroundWithId("Oaq79bhv53") {
(gameScore: PFObject?, error: NSError?) -> Void in
if error == nil && gameScore != nil {
println(gameScore)
} else {
println("error")
}
}
I figured it out!
user.signUpInBackgroundWithBlock{(succeeded: Bool, signUpError: NSError?) -> Void in
Swift 4.2:
query.getObjectInBackground(withId: "YourId") { (gameScore, error) in
if error == nil {
// Success!
print(gameScore)
} else {
// Fail!
}
}

Resources