스위프트 2 : 호출이 발생할 수 있지만 '시도'로 표시되지 않고 오류가 처리되지 않습니다.


161

Xcode 7 베타를 설치하고 빠른 코드를 Swift 2로 변환 한 후 알아낼 수없는 코드에 문제가 있습니다. 나는 Swift 2가 새로운 것을 알고 있으므로 그것에 대해 아무것도 없기 때문에 검색하고 알아 내고 질문을해야합니다.

오류는 다음과 같습니다.

호출은 던질 수 있지만 'try'로 표시되지 않고 오류가 처리되지 않습니다.

암호:

func deleteAccountDetail(){
        let entityDescription = NSEntityDescription.entityForName("AccountDetail", inManagedObjectContext: Context!)
        let request = NSFetchRequest()
        request.entity = entityDescription

        //The Line Below is where i expect the error
        let fetchedEntities = self.Context!.executeFetchRequest(request) as! [AccountDetail]

        for entity in fetchedEntities {
        self.Context!.deleteObject(entity)
        }

        do {
            try self.Context!.save()
        } catch _ {
        }

    }

스냅 사진: 여기에 이미지 설명을 입력하십시오

답변:


168

이미 save()전화를 걸 었던 것처럼 오류를 잡아야하며 여기에서 여러 오류를 처리 try하므로 다음과 같이 단일 do-catch 블록에서 여러 통화를 순차적으로 수행 할 수 있습니다 .

func deleteAccountDetail() {
    let entityDescription = NSEntityDescription.entityForName("AccountDetail", inManagedObjectContext: Context!)
    let request = NSFetchRequest()
    request.entity = entityDescription

    do {
        let fetchedEntities = try self.Context!.executeFetchRequest(request) as! [AccountDetail]

        for entity in fetchedEntities {
            self.Context!.deleteObject(entity)
        }

        try self.Context!.save()
    } catch {
        print(error)
    }
}

또는 @ bames53이 아래 주석에서 지적했듯이 오류가 발생했을 때 오류를 포착하지 않는 것이 좋습니다. 메소드 를 호출 throws한 다음 메소드 try를 호출하여 메소드를 호출 할 수 있습니다 . 예를 들면 다음과 같습니다.

func deleteAccountDetail() throws {
    let entityDescription = NSEntityDescription.entityForName("AccountDetail", inManagedObjectContext: Context!)
    let request = NSFetchRequest()

    request.entity = entityDescription

    let fetchedEntities = try Context.executeFetchRequest(request) as! [AccountDetail]

    for entity in fetchedEntities {
        self.Context!.deleteObject(entity)
    }

    try self.Context!.save()
}

이것은 내가 알아낼 수 있도록 도와줍니다. 감사합니다.
Farhad

5
실제로 여기에서 예외를 잡을 필요는 없습니다. try함수 호출에 키워드를 추가 하고이 함수를로 선언하는 것이 가능합니다 func deleteAccountDetail() throw. 또는 주어진 입력에 대해 함수가 throw되지 않도록 보장하면을 사용할 수 있습니다 try!.
bames53

4
나는 이것을 nitpick으로 가져 오지 않지만 실제로 예외가 발생하는 대부분의 장소에서 예외를 포착하지 않는 예외 기반 오류 처리는 상당히 중요하기 때문에. 예외를 잡는 것이 적합한 장소는 세 가지가 있습니다. 다른 모든 곳에서 코드는 예외를 명시 적으로 처리해서는 안되며, deinit()정리 (RAII)를 위해 암시 적 호출을 사용하거나 때로는 defer임시 정리를 수행 하는 데 사용해야 합니다. 자세한 내용은 exceptionsafecode.com을 참조하십시오 (C ++에 대한 설명이지만 기본 원칙은 Swift 예외에도 적용됩니다).
bames53

그러나 어떻게 함수를 실행 하시겠습니까? @ bames53 방법으로 가면?
Farhad

1
@NickMoore Swift 개발자가 전화를해서 선택하는 것이 실제로는 달라지지 않습니다. Swift의 새로운 오류 처리 시스템은 예외가 구현되어 해당 용어가 산업 전반에 걸쳐 일반적으로 사용됩니다.
bames53

41

throwsSwift에서 선언 된 함수를 호출 할 때는 try또는로 함수 호출 사이트에 주석을 달아야합니다 try!. 예를 들어, 던지는 기능이 있다면 :

func willOnlyThrowIfTrue(value: Bool) throws {
  if value { throw someError }
}

이 함수는 다음과 같이 호출 될 수 있습니다.

func foo(value: Bool) throws {
  try willOnlyThrowIfTrue(value)
}

여기에 호출에 주석을 달아, try이 함수는 예외를 발생시킬 수 있으며 다음 코드 줄은 실행되지 않을 수 있음을 독자에게 호출합니다. throws이 함수는 예외를 던질 수 있기 때문에이 함수에 주석을 달아야합니다 (예 : 던질 때 예외 를 자동으로 willOnlyThrowIfTrue()다시 던질 foo것입니다).

던질 가능성이 있다고 선언되었지만 올바른 입력을 제공하기 때문에 케이스에서 던지지 않는 함수를 호출하려면을 사용할 수 있습니다 try!.

func bar() {
  try! willOnlyThrowIfTrue(false)
}

이렇게하면 코드가 발생하지 않는다고 보장 할 때 예외 전파를 비활성화하기 위해 추가 상용구 코드를 넣을 필요가 없습니다.

try!런타임에 적용됩니다. 사용 try!하고 함수가 종료되면 프로그램 실행이 런타임 오류와 함께 종료됩니다.

대부분의 예외 처리 코드는 위와 같습니다. 예외가 발생할 때 예외를 위쪽으로 전파하거나 다른 예외가 배제되도록 조건을 설정합니다. 코드에서 다른 리소스를 정리하면 객체 소멸 (예 :) deinit()또는 defered 코드 를 통해 발생해야합니다 .

func baz(value: Bool) throws {

  var filePath = NSBundle.mainBundle().pathForResource("theFile", ofType:"txt")
  var data = NSData(contentsOfFile:filePath)

  try willOnlyThrowIfTrue(value)

  // data and filePath automatically cleaned up, even when an exception occurs.
}

어떤 이유로 든 실행해야하지만 deinit()기능 이 아닌 코드를 정리하는 경우을 사용할 수 있습니다 defer.

func qux(value: Bool) throws {
  defer {
    print("this code runs when the function exits, even when it exits by an exception")
  }

  try willOnlyThrowIfTrue(value)
}

예외 거래는 단순히 그들을 통해가는 길에 정리를하고, 발신자에게 위로 전파 것을 대부분의 코드 deinit()defer. 이것은 대부분의 코드가 오류로 무엇을해야하는지 모르기 때문입니다. 무엇이 잘못되었는지는 알지만 오류에 대한 조치를 알기 위해 일부 상위 코드가 수행하려는 작업에 대한 정보가 충분하지 않습니다. 사용자에게 대화 상자를 표시하는 것이 적절한 지 또는 다시 시도 해야하는지 또는 다른 것이 적합한 지 알 수 없습니다.

그러나 높은 수준의 코드는 오류 발생시 수행 할 작업을 정확하게 알고 있어야합니다. 따라서 예외는 특정 오류가 처음 발생한 위치에서 처리 할 수있는 위치까지 버블 링되도록합니다.

예외 처리는 catch명령문을 통해 수행됩니다 .

func quux(value: Bool) {
  do {
    try willOnlyThrowIfTrue(value)
  } catch {
    // handle error
  }
}

각각 다른 종류의 예외를 잡는 catch 문을 여러 개 가질 수 있습니다.

  do {
    try someFunctionThatThowsDifferentExceptions()
  } catch MyErrorType.errorA {
    // handle errorA
  } catch MyErrorType.errorB {
    // handle errorB
  } catch {
    // handle other errors
  }

예외가있는 모범 사례에 대한 자세한 내용은 http://exceptionsafecode.com/을 참조하십시오 . C ++을 특별히 목표로했지만 Swift 예외 모델을 검토 한 후에 기본 사항이 Swift에도 적용된다고 생각합니다.

Swift 구문 및 오류 처리 모델에 대한 자세한 내용 은 Swift 프로그래밍 언어 (Swift 2 시험판) 책을 참조하십시오 .


기본적으로 catch 자체가 오류를 처리 할 수 ​​있습니까? 또는 입력 기능
Farhad

1
@BrianS 특히 '입력 함수'와 관련하여 정확히 무엇을 요구하는지 확실하지 않지만 '캐치'는 기본적으로 예외 상황에서 '처리'와 동의어입니다. 다시 말해, 프로그래밍 언어와 관련하여 예외를 포착하고 예외를 처리하는 것은 동일합니다.
bames53

조용히 이해할 수없는 오류가 하나 있습니다. 도와주세요. Invalid conversion from throwing function of type '() throws -> _' to non-throwing function type '(NSData?, NSURLResponse?, NSError?) -> Void'
Farhad

@BrianS 어딘가에 서명이 잘못된 함수를 사용하고있는 것 같습니다. NSData?, NSURLResponse?, NSError?인수로 사용 되는 함수가 제공 될 것으로 예상 되지만 인수를 사용하지 않는 함수를 제공합니다.
bames53

또는 무언가 예외를 throw하도록 선언되지 않은 함수를 기대하고 예외를 throw하는 함수를 제공합니다.
bames53
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.