Когда вы объявляете ссылочную переменную (т. е. объект), вы действительно создаете указатель на объект. Рассмотрим следующий код, в котором вы объявляете переменную примитивного типа int
:
int x;
x = 10;
В этом примере переменная x является int
, и Java инициализирует ее для 0. Когда вы назначаете его 10 во второй строке, ваше значение 10 записывается в ячейку памяти, на которую указывает x.
Но когда вы пытаетесь объявить ссылочный тип, произойдет что-то другое. Возьмите следующий код:
Integer num;
num = new Integer(10);
Первая строка объявляет переменную с именем num
, но она не содержит примитивного значения. Вместо этого он содержит указатель (потому что тип Integer
является ссылочным типом). Поскольку вы еще не указали, что указать на Java, он устанавливает значение null, что означает «Я ничего не указываю».
Во второй строке ключевое слово new
используется для создания экземпляра (или создания ) объекту типа Integer и переменной указателя num
присваивается этот объект. Теперь вы можете ссылаться на объект, используя оператор разыменования .
(точка).
Exception
, о котором вы просили, возникает, когда вы объявляете переменную, но не создавали объект. Если вы попытаетесь разыменовать num
. Перед созданием объекта вы получите NullPointerException
. В самых тривиальных случаях компилятор поймает проблему и сообщит вам, что «num не может быть инициализирован», но иногда вы пишете код, который непосредственно не создает объект.
Например, вы можете имеют следующий метод:
public void doSomething(SomeObject obj) {
//do something to obj
}
В этом случае вы не создаете объект obj
, скорее предполагая, что он был создан до вызова метода doSomething
. К сожалению, этот метод можно вызвать следующим образом:
doSomething(null);
В этом случае obj
имеет значение null. Если метод предназначен для того, чтобы что-то сделать для переданного объекта, целесообразно бросить NullPointerException
, потому что это ошибка программиста, и программисту понадобится эта информация для целей отладки.
Альтернативно, там могут быть случаи, когда цель метода заключается не только в том, чтобы работать с переданным в объекте, и поэтому нулевой параметр может быть приемлемым. В этом случае вам нужно будет проверить нулевой параметр и вести себя по-другому. Вы также должны объяснить это в документации. Например, doSomething
может быть записано как:
/**
* @param obj An optional foo for ____. May be null, in which case
* the result will be ____.
*/
public void doSomething(SomeObject obj) {
if(obj != null) {
//do something
} else {
//do something else
}
}
Наконец, Как определить исключение & amp; причина использования Трассировки стека
Вы должны поймать ошибку так же, как вы уже делаете для своего вызова save()
, и поскольку вы обрабатываете несколько ошибок здесь, вы можете try
несколько вызовов последовательно в одном блоке блокировки наложения, например :
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()
}
При вызове функции, объявленной с помощью throws
в Swift, вы должны аннотировать сайт вызова функции с помощью try
или try!
. Например, с учетом функции throwing:
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()
) или иногда через defer
ed код.
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 и обработки ошибок см. В книге The Swift Язык программирования (Swift 2 Prerelease) .
Invalid conversion from throwing function of type '() throws -> _' to non-throwing function type '(NSData?, NSURLResponse?, NSError?) -> Void'
– Farhad
9 June 2015 в 19:52
NSData?, NSURLResponse?, NSError?
как аргументы, но вы даете ей функцию, которая не принимает никаких аргументов.
– bames53
9 June 2015 в 19:57
try
в вызов функции и объявить эту функцию какfunc deleteAccountDetail() throw
. Или, если вы гарантировали, что функция не будет выбрасывать для данного ввода, вы можете использоватьtry!
. – bames53 9 June 2015 в 16:32deinit()
для очистки (т. Е. RAII) или иногда использоватьdefer
для выполнения некоторой специальной очистки. Дополнительную информацию см. В разделе exceptionsafecode.com (он говорит о C ++, но основные принципы применимы и к исключениям Swift). – bames53 9 June 2015 в 16:34