Swift 2에서 사용자 정의 메시지로 오류 / 예외를 발생시키는 가장 간단한 방법은 무엇입니까?


136

Swift 2에서 다른 여러 언어로 익숙한 작업을하고 싶습니다. 사용자 정의 메시지로 런타임 예외를 throw하십시오. 예를 들어 (Java) :

throw new RuntimeException("A custom message here")

ErrorType 프로토콜을 준수하는 열거 형 유형을 던질 수 있다는 것을 알고 있지만 던지는 모든 유형의 오류에 대해 열거 형을 정의하고 싶지는 않습니다. 이상적으로는 위의 예를 가능한 한 유사하게 모방하고 싶습니다. ErrorType 프로토콜을 구현하는 사용자 정의 클래스를 만들려고 시도했지만 해당 프로토콜에 필요한 것이 무엇인지 파악할 수도 없습니다 ( documentation 참조 ). 아이디어?


2
스위프트 2 스로우 / 캐치는 예외가 아닙니다.
— zaph

답변:


194

가장 간단한 방법은 정의 아마 하나의 정의를 enum단지 하나 case있다 String첨부 :

enum MyError: ErrorType {
    case runtimeError(String)
}

또는 Swift 4 기준 :

enum MyError: Error {
    case runtimeError(String)
}

사용 예는 다음과 같습니다.

func someFunction() throws {
    throw MyError.runtimeError("some message")
}
do {
    try someFunction()
} catch MyError.runtimeError(let errorMessage) {
    print(errorMessage)
}

기존 Error유형 을 사용하려는 경우 가장 일반적인 유형 NSError은이며 사용자 정의 메시지로 유형을 작성하고 던지는 팩토리 메소드를 작성할 수 있습니다.


안녕하세요, 귀하가이 답변을 게시 한 지 1 년이되었다는 것을 알고 있지만 String귀하 의 내부 를 알아볼 수 있는지 알고 싶습니다. errorMessage그렇다면 어떻게해야합니까?
— Renan Camaforte 1

1
@RenanCamaforte 죄송합니다. 질문을 이해하지 못합니까? 는 String여기 연관된다 MyError.RuntimeError(시간에 세트 throw), 당신은에서 그것에 접근 획득 catch(과를 let errorMessage).
— Arkku

1
가장 간단한 솔루션을 요청했습니다. 사용자 정의 열거 형, 함수 등을 만들 때의 해결책은 간단하지 않습니다. 나는 적어도 한 가지 방법을 알고 있지만 objective-C를위한 것이므로 게시하지 않을 것입니다
— Vyachaslav Gerchicov

3
@VyachaslavGerchicov 질문에 지정된 Swift에 대한 간단한 방법을 모른다면 이것이 가장 간단한 방법 일 것입니다. . (또한이 답변은 기본적으로 열거 형에 대한 일회성 일회성 정의이며, 함수 및 해당 호출은 솔루션의 일부가 아닌 사용법의 예입니다.
— Arkku

1
@Otar 그렇습니다.하지만…에 대해 이야기하고 있지만 try!여기서는 사용되지 않습니다. 당신은 실제로 어떤 종류의 없이는 잠재적으로 던지는 전화를 걸 수 없습니다 try. (또한 코드의 일부는 실제 솔루션이 아니라 사용 예입니다.)
— Arkku

136

가장 간단한 방법은 다음을 String준수하는 것입니다 Error.

extension String: Error {}

그런 다음 문자열을 던질 수 있습니다.

throw "Some Error"

문자열 자체를 localizedString오류 로 만들기 위해 대신 확장 할 수 있습니다 LocalizedError.

extension String: LocalizedError {
    public var errorDescription: String? { return self }
}

이것은 영리하지만 localizedDescription문자열 자체 로 만드는 방법이 있습니까?
— 빌라 포수 01. 25. 17.

1
매우 우아한 방법!
— Vitaliy Gozhenko

1
정말 우아합니다! 그러나 다음과 같은 메시지가 테스트 대상에 나를 위해 분해 Redundant conformance of 'String' to protocol 'Error':(
— 알렉산더 Borisenko에게

2
어떤 이유로 든 이것이 효과가 없습니다. error.localizedDescription문자열을 던진 후 구문 분석 할 때 작업을 완료 할 수 없다고 말합니다 .
— Noah Allen

1
경고 :이 확장으로 인해 외부 라이브러리에 문제가 발생했습니다. 여기 내 예가 있습니다. 오류를 관리하는 모든 타사 라이브러리에서 가능합니다. String이 Error를 준수하도록하는 확장을 피할 수 있습니다.
— Bryan W. Wagner

20

@ nick-keets의 솔루션은 가장 우아하지만 다음 컴파일 시간 오류로 테스트 대상에서 나에게 고장났습니다.

Redundant conformance of 'String' to protocol 'Error'

다른 접근 방식이 있습니다.

struct RuntimeError: Error {
    let message: String

    init(_ message: String) {
        self.message = message
    }

    public var localizedDescription: String {
        return message
    }
}

그리고 사용하려면 :

throw RuntimeError("Error message.")

19

이 멋진 버전을 확인하십시오. 아이디어는 String 및 ErrorType 프로토콜을 모두 구현하고 오류의 rawValue를 사용하는 것입니다.

enum UserValidationError: String, Error {
  case noFirstNameProvided = "Please insert your first name."
  case noLastNameProvided = "Please insert your last name."
  case noAgeProvided = "Please insert your age."
  case noEmailProvided = "Please insert your email."
}

용법:

do {
  try User.define(firstName,
                  lastName: lastName,
                  age: age,
                  email: email,
                  gender: gender,
                  location: location,
                  phone: phone)
}
catch let error as User.UserValidationError {
  print(error.rawValue)
  return
}

여전히 필요에 따라,이 방법에 약간의 도움이 될 것 같습니다 as User.UserValidationError과 그 위에을 .rawValue. 대신 구현하는 경우에는 CustomStringConvertible같은 var description: String { return rawValue },을 통해 갈 필요없이 열거 구문을 사용하여 사용자 정의 설명을 얻을 수 유용 할 수 있습니다 rawValue당신이 그것을 인쇄 할 경우 모든 장소에서.
— Arkku

1
더 나은 .rawValue 반환 localizedDescription 메소드를 구현
— DanSkeel

16

스위프트 4 :

에 따라 :

https://developer.apple.com/documentation/foundation/nserror

사용자 정의 예외를 정의하지 않으려면 다음과 같이 표준 NSError 객체를 사용할 수 있습니다.

import Foundation

do {
  throw NSError(domain: "my error description", code: 42, userInfo: ["ui1":12, "ui2":"val2"] ) 
}
catch let error as NSError {
  print("Caught NSError: \(error.localizedDescription), \(error.domain), \(error.code)")
  let uis = error.userInfo 
  print("\tUser info:")
  for (key,value) in uis {
    print("\t\tkey=\(key), value=\(value)")
  }
}

인쇄물:

Caught NSError: The operation could not be completed, my error description, 42
    User info:
        key=ui1, value=12
        key=ui2, value=val2

이를 통해 사용자 정의 문자열과 숫자 코드 및 필요한 모든 추가 데이터가 포함 된 사전을 모든 유형으로 제공 할 수 있습니다.

NB : OS = Linux (Ubuntu 16.04 LTS)에서 테스트되었습니다.


12

추가 확장, 열거 형, 클래스 등이없는 가장 간단한 솔루션 :

NSException(name:NSExceptionName(rawValue: "name"), reason:"reason", userInfo:nil).raise()

2
레. 내 대답에 대한 귀하의 의견, 이것은 정의 및 열거 또는 확장을 한 번 정의하는 것이 다소 복잡 하다고 임의로 결정했다는 의미에서 간단합니다 . 따라서 네 대답에는 "setup"줄이 없지만 모든 예외를 희생시키면서 기억하기 어려운 복잡하고 스위프트가 아닌 ( 주문 raise()대신 throw) 철자를 사용하십시오. 귀하의 솔루션과 예외가 발생한 장소의 수를 곱 throw Foo.Bar("baz")하거나 throw "foo"곱한 값을 비교하십시오 – IMO 일회성 연장 또는 열거 형의 일회성 요금은와 같은 것보다 훨씬 선호됩니다 NSExceptionName.
— Arkku

@Arkku 예를 들어 postNotification2-3 개의 매개 변수가 필요하며 선택기는이 매개 변수와 유사합니다. 더 적은 입력 매개 변수를 허용하도록 각 프로젝트를 재정의 Notification및 / 또는 무시 NotificationCenter합니까?
— Vyachaslav Gerchicov

1
아니요, 본인의 답변으로는 솔루션을 사용하지 않을 것입니다. 나는 내가 스스로 할 일이 아니기 때문에 질문에 대답하기 위해 그것을 게시했습니다. 어쨌든, 그것은 요점 외에 있습니다 : 나는 당신의 대답이 광산이나 Nick Keets의 것보다 사용하기 가 훨씬 더 복잡하다는 의견에 견딜 수 있습니다 . 물론 String준수하기 위해 확장 하는 Error것이 너무 놀랍거나 MyError열거 형이 너무 모호한 경우와 같이 고려해야 할 다른 유효한 점이 있습니다 (개인적으로 두 가지 모두에 예라고 대답하고 대신 각 오류에 대해 별도의 열거 형 사례를 수행합니다. throw ThisTypeOfError.thisParticularCase).
— Arkku

6

@Nick keets 답변을 기반으로 한 더 완전한 예는 다음과 같습니다.

extension String: Error {} // Enables you to throw a string

extension String: LocalizedError { // Adds error.localizedDescription to Error instances
    public var errorDescription: String? { return self }
}

func test(color: NSColor) throws{
    if color == .red {
        throw "I don't like red"
    }else if color == .green {
        throw "I'm not into green"
    }else {
        throw "I like all other colors"
    }
}

do {
    try test(color: .green)
} catch let error where error.localizedDescription == "I don't like red"{
    Swift.print ("Error: \(error)") // "I don't like red"
}catch let error {
    Swift.print ("Other cases: Error: \(error.localizedDescription)") // I like all other colors
}

빠른 블로그에 처음 게시 : http://eon.codes/blog/2017/09/01/throwing-simple-errors/


1
TBH : 나는 이제 막throw NSError(message: "err", code: 0)
— eonist

그래서 당신은 당신 자신의 예를 사용하지 않습니까? : D 아, 그리고 첫 번째 주장은 domain그렇지 message않습니까?
— NRitH

1
당신의 권리, 도메인. 그리고 아니요, 코드에 설탕을 너무 많이 넣습니다. 나는 보통 작은 프레임 워크와 모듈을 많이 만들고 편리한 확장 설탕을 낮게 유지하려고합니다. 요즘 나는 결과와 NSError 사이의 혼합을 사용하려고
— eonist

6

오류를 잡을 필요가없고 응용 프로그램을 즉시 중지하려는 경우 fatalError를 사용할 수 있습니다. fatalError ("Custom message here")


3
이것은 잡힐 수있는 오류를 발생시키지 않습니다. 앱이 중단됩니다.
— Adil Hussain

4

@ Alexander-Borisenko의 답변이 마음에 들지만 오류로 잡힐 때 현지화 된 설명이 반환되지 않았습니다. 대신 LocalizedError를 사용해야하는 것 같습니다.

struct RuntimeError: LocalizedError
{
    let message: String

    init(_ message: String)
    {
        self.message = message
    }

    public var errorDescription: String?
    {
        return message
    }
}

자세한 내용은 이 답변 을 참조하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.