MASTG-KNOW-0065 例外処理 (Exception Handling)
例外はアプリケーションが正常ではない状態やエラーのある状態になった場合によく発生します。 例外処理のテストとは、ログ出力メカニズムや UI を介して機密情報を開示することなく、アプリケーションが例外を処理して安全な状態になることを確認することです。
但し、Objective-C の例外処理は Swift とはまったく異なることに注意します。従来の Objective-C コードと Swift コードの両方で書かれたアプリケーションで二つの概念を橋渡しすることは問題になる可能性があります。
Objective-C の例外処理
Objective-C には二種類のエラーがあります。
NSException:
NSException
はプログラミングエラーや低レベルエラー (0 による除算、配列の境界外アクセスなど) を処理するために使用されます。 NSException
は raise
によりレイズされるか、または @throw
でスローされます。catch されない場合、この例外は unhandled 例外ハンドラを呼び出し、ステートメントをログ出力します (ログ出力はプログラムを停止します) 。@try
-@catch
ブロックを使用している場合、@catch
はその例外から回復できます。
@try {
//do work here
}
@catch (NSException *e) {
//recover from exception
}
@finally {
//cleanup
NSException
の使用にはメモリ管理の落とし穴があることに気をつけます。finally ブロック 内で try ブロックでの 割り当てをクリーンアップする 必要があります。@catch
ブロックで NSError
をインスタンス化することにより NSException
オブジェクトを NSError
に変換できることに注意します。
NSError:
NSError
は他のすべてのタイプの エラー に使用されます。Cocoa フレームワークの一部の API では何らかの問題が発生した場合に失敗時コールバックのオブジェクトしてエラーを提供します。それらを提供しないものは NSError
オブジェクトへのポインタを参照渡しします。成功または失敗を示す NSError
オブジェクトへのポインタを取るメソッドに、BOOL
の戻り値型を提供することはよい習慣です。戻り値の型がある場合、エラーの場合に nil
を戻すことを確認します。NO
または nil
が戻される場合には、エラーや失敗の理由を調べることができます。
Swift の例外処理
Swift (2~5) の例外処理はまったく異なります。try-catch ブロックは NSException
を処理するためのものではありません。そのブロックは Error
(Swift 3) または ErrorType
(Swift 2) プロトコルに準拠するエラーを処理するために使用されます。一つのアプリケーション内で Objective-C と Swift コードを組み合わせる場合、これは困難になることがあります。したがって、両方の言語で書かれたプログラムでは NSException
よりも NSError
が好まれます。さらに、Objective-C ではエラー処理はオプトインですが、Swift では明示的に throws
を処理する必要があります。エラーを throw する際の変換には、Apple のドキュメント をご覧ください。 エラーを throw するメソッドは throws
キーワードを使用します。Result
タイプは成功または失敗を表します。Result, Swift 5 での Result の使用方法, Swift での Result タイプの威力 を参照してください。Swift でエラーを処理する 方法は四つあります。
関数からその関数を呼び出すコードにエラーを伝えることができます。この場合、
do-catch
はありません。単に実際のエラーを throw するthrow
があるか、throw するメソッドを実行するtry
があります。try
を含むメソッドにはthrows
キーワードも必要です。
func dosomething(argumentx:TypeX) throws {
try functionThatThrows(argumentx: argumentx)
}
do-catch
文を使用してエラーを処理します。ここでは以下のパターンを使用できます。func doTryExample() { do { try functionThatThrows(number: 203) } catch NumberError.lessThanZero { // Handle number is less than zero } catch let NumberError.tooLarge(delta) { // Handle number is too large (with delta value) } catch { // Handle any other errors } } enum NumberError: Error { case lessThanZero case tooLarge(Int) case tooSmall(Int) } func functionThatThrows(number: Int) throws -> Bool { if number < 0 { throw NumberError.lessThanZero } else if number < 10 { throw NumberError.tooSmall(10 - number) } else if number > 100 { throw NumberError.tooLarge(100 - number) } else { return true } }
エラーを optional 値として処理します。
let x = try? functionThatThrows() // In this case the value of x is nil in case of an error.
try!
式を使用して、エラーが発生しないことを assert します。一般的なエラーを
Result
戻り値として処理します。
enum ErrorType: Error {
case typeOne
case typeTwo
}
func functionWithResult(param: String?) -> Result<String, ErrorType> {
guard let value = param else {
return .failure(.typeOne)
}
return .success(value)
}
func callResultFunction() {
let result = functionWithResult(param: "OWASP")
switch result {
case let .success(value):
// Handle success
case let .failure(error):
// Handle failure (with error)
}
}
ネットワークおよび JSON デコーディングエラーを
Result
タイプで処理します。
struct MSTG: Codable {
var root: String
var plugins: [String]
var structure: MSTGStructure
var title: String
var language: String
var description: String
}
struct MSTGStructure: Codable {
var readme: String
}
enum RequestError: Error {
case requestError(Error)
case noData
case jsonError
}
func getMSTGInfo() {
guard let url = URL(string: "https://raw.githubusercontent.com/OWASP/mastg/master/book.json") else {
return
}
request(url: url) { result in
switch result {
case let .success(data):
// Handle success with MSTG data
let mstgTitle = data.title
let mstgDescription = data.description
case let .failure(error):
// Handle failure
switch error {
case let .requestError(error):
// Handle request error (with error)
case .noData:
// Handle no data received in response
case .jsonError:
// Handle error parsing JSON
}
}
}
}
func request(url: URL, completion: @escaping (Result<MSTG, RequestError>) -> Void) {
let task = URLSession.shared.dataTask(with: url) { data, _, error in
if let error = error {
return completion(.failure(.requestError(error)))
} else {
if let data = data {
let decoder = JSONDecoder()
guard let response = try? decoder.decode(MSTG.self, from: data) else {
return completion(.failure(.jsonError))
}
return completion(.success(response))
}
}
}
task.resume()
}
Last updated
Was this helpful?