it-roy-ru.com

Swift 2: Call может выдать, но он не помечен как 'try', и ошибка не обработана

После того, как я установил бета-версию Xcode 7 и преобразовал свой код Swift в Swift 2, у меня возникла проблема с кодом, которую я не могу понять. Я знаю, что Swift 2 является новым, поэтому я ищу и выясняю, так как в этом нет ничего, я должен написать вопрос.

вот ошибка:

Вызов может скинуть, но он не помечен как "попытаться" и ошибка не обрабатывается

Код:

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 _ {
        }

    }

Снимок: enter image description here

146
Farhad

Вы должны отловить ошибку так же, как вы уже делаете для своего вызова 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()
}
154
Mick MacCallum

При вызове функции, объявленной с throws в Swift, вы должны аннотировать сайт вызова функции с 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) .

38
bames53