- Review various methods for handling errors in swift
- Objective-C’s NSError
- Swift’s try/catch/throws
- Result<T, U> type
- Exceptions & Assertions
You are given the Error type Fortunately most methods using this style of error handling have been bridge to use swifts try/catch mechanism
NSError *error = nil;
NSString *string = [NSString stringWithContentsOfFile:@"test.txt"
encoding:NSUTF8StringEncoding error:&error];
if (!string) {
NSLog(@"File could not be read!");
}
if (error) {
NSLog(@"%@", error.localizedDescription);
}
- Return value is most relevant for checking whether an operation was successful or not [1]
- Methods can return errors, but still successfully return a value
NSString *string = [NSString stringWithContentsOfFile:@"test.txt"
encoding:NSUTF8StringEncoding error:nil];
Swift 2+ uses throws instead of NSError Objective-C methods are bridged to Swift accordingly:
Functions marked with throws need to be handling
You need to choose one of these 4 approaches:
- Handle the error with a do/catch block
- Use forced-try: try!
- Use optional: try? - returns an optional value
- Propagate the error further up the call stack by declaring calling function as throws
// Option 1
do {
let content = try String(contentsOfFile: “test.txt", encoding: NSUTF8StringEncoding)
} catch let error {
print(error)
}
// Option 2
let content = try! String(contentsOfFile: “test.txt", encoding: NSUTF8StringEncoding)
// Option 3
let content: String? = try? String(contentsOfFile: “test.txt", encoding: NSUTF8StringEncoding)
// Option 4
func someFunc() throws {
try String(contentsOfFile: "test.text", encoding: String.Encoding.utf8)
}
do {
try someFunc()
} catch {
}
How do you know which types of errors to catch? Header documentation! Unfortunately throws has no type information
enum FileReadError: Error {
case InvalidFilePath
case InvalidEncoding
case IncorrectFileFormat(actualFileFormat: String)
}
/**
- Returns: The content of the file
- Throws: `FileReadError.InvalidFilePath` if file could not be read;
`FileReadError.InvalidEncoding` if file encoding does not match expected encoding;
`FileReadError.IncorrectFileFormat` if file format does not match specified one
*/
func readFile(path: String) throws -> Data {
// ...
throw FileReadError.InvalidFilePath
}
do {
try readFile("test.txt")
} catch FileReadError.InvalidFilePath {
print("Invalid filepath")
} catch FileReadError.InvalidEncoding {
print("Invalid encoding")
} catch let FileReadError.IncorrectFileFormat(actualFileFormat) {
print("Unexpected file format: \(actualFileFormat)")
} catch {
print("Unhandled Error!")
}
Errors don’t have type information
Error handling doesn’t work for asynchronous code
//1
func fetchUser(completion: @escaping (User) -> Void) {
let request = URLRequest(url: URL(string: "https://www.google.com")!)
let session = URLSession.shared()
session.dataTaskWithRequest(request) { (data, response, error) -> Void in
// error handling happens in callback
let user = //myUser
completion(user)
}
}
// 2
func fetchUser(completion: (Void throws -> User) -> Void) {
}
Result type can represent value or error depending on result of operation
Can be used for synchronous and asynchronous code
func search(searchString: String) -> Result<Predictions, SearchError>
func fetchAllTrips(callback: Result<[JSONTrip], Reason> -> Void) {
// in case of success
var trips: [JSONTrip] = [/*...*/]
callback(.success(trips))
// in case of error
var reason: Reason = .NoData
callback(.failure(reason))
}
func handleSearchResult(result: Result<Predictions, Reason>) -> Void {
switch result {
case let .success(predictions):
self.locations = predictions.predictions
case .failure(_):
self.errorHandler.displayErrorMessage(
"The search returned an error, sorry!"
)
}
}
Objective-C provides exceptions, Swift does not Objective-C exceptions should not be caught, they are not intended for error handling Exceptions are used to crash the app to make you aware of a programming error
Are used to state and verify assumptions Typically only used at debug time Objective-C: NSAssert… Swift: assert, assertionFailure, fatalError,…
-
Swift uses Error and throws for error handling
-
Swift error handling has limitations (no type info, not suitable for async code) - Result type is a good alternative
-
Exceptions and assertions are used for unrecoverable errors