5月27日 10:38
What is the error handling mechanism in Swift? How to use throws, throw, try, and catch?
What is the error handling mechanism in Swift? How to use throws, throw, try, and catch to handle errors?
Swift provides a comprehensive error handling mechanism that allows developers to gracefully handle runtime errors. Swift's error handling model is similar to exception handling but is more type-safe and controllable.
Defining Errors:
- Use the
Errorprotocol to define error types - Can use enums to define specific error cases
- Can associate error information
- Example:
swift
enum NetworkError: Error { case invalidURL case requestFailed(Int) case noData case decodingError } enum FileError: Error { case notFound case permissionDenied case corrupted }
Throwing Errors:
- Use the
throwskeyword to mark functions that may throw errors - Use the
throwkeyword to throw errors - Example:
swift
func fetchData(from urlString: String) throws -> Data { guard let url = URL(string: urlString) else { throw NetworkError.invalidURL } let (data, response) = try URLSession.shared.data(from: url) guard let httpResponse = response as? HTTPURLResponse else { throw NetworkError.requestFailed(0) } guard httpResponse.statusCode == 200 else { throw NetworkError.requestFailed(httpResponse.statusCode) } return data }
Handling Errors:
-
Using try-catch:
swiftdo { let data = try fetchData(from: "https://api.example.com/data") print("Data received: \(data)") } catch NetworkError.invalidURL { print("Invalid URL") } catch NetworkError.requestFailed(let statusCode) { print("Request failed with status: \(statusCode)") } catch { print("Unexpected error: \(error)") } -
Using try?:
- Converts errors to optional values
- Returns nil if an error occurs
- Example:
swift
let data = try? fetchData(from: "https://api.example.com/data") if let data = data { print("Data received: \(data)") } else { print("Failed to fetch data") }
-
Using try!:
- Force unwrapping, used when you're certain no error will be thrown
- Triggers a runtime error if an error is thrown
- Example:
swift
let data = try! fetchData(from: "https://api.example.com/data") print("Data received: \(data)")
defer Statement:
- Performs cleanup operations before exiting a code block
- Executes regardless of whether an error occurs
- Example:
swift
func processFile(at path: String) throws { let fileHandle = try FileHandle(forReadingFrom: URL(fileURLWithPath: path)) defer { fileHandle.closeFile() } let data = fileHandle.readDataToEndOfFile() return data }
rethrow:
- Rethrows caught errors
- Used in wrapper functions
- Example:
swift
func processData(_ urlString: String) throws -> Data { let data = try fetchData(from: urlString) return data }
Result Type:
- Use
Result<Success, Failure>type to handle errors - More functional error handling approach
- Example:
swift
func fetchDataResult(from urlString: String) -> Result<Data, Error> { guard let url = URL(string: urlString) else { return .failure(NetworkError.invalidURL) } let (data, response) = URLSession.shared.synchronousData(with: url) return .success(data) } switch fetchDataResult(from: "https://api.example.com/data") { case .success(let data): print("Data received: \(data)") case .failure(let error): print("Error: \(error)") }
Best Practices:
- Use enums to define clear error types
- Add associated values to errors for more information
- Use
try?for recoverable errors - Use
deferto ensure proper resource cleanup - Use
Resulttype where appropriate