Objective-C: утверждение против исключения против ошибки

79

В Какао, когда мне следует использовать NSAssert, NSException, NSError?

Вот о чем я думал:

NSAssert - при создании любой клиентской программы, используемой для собственной выгоды программистов, для двойной проверки правил, соглашений, предположений или предварительных условий и постусловий?

NSException - при создании сторонней библиотеки для других программистов, использующих библиотеку, чтобы они сразу знали, когда ввод недействителен?

NSError - при взаимодействии с внешней системой для получения данных, таких как файл, база данных или веб-служба, которые не гарантируют мне результат?

Тобиас
источник

Ответы:

103

NSAssert вызовет исключение. Таким образом, NSAssert должен быть коротким и простым способом написания и проверки любых предположений, которые вы сделали в своем коде. Это (на мой взгляд) не альтернатива исключениям, а просто ярлык. Если утверждение не выполняется, значит, в вашем коде что-то пошло не так, и программа не должна продолжаться.

Следует отметить, что NSAssert не будет компилироваться в ваш код в сборке выпуска, поэтому обычно это используется для проверки работоспособности во время разработки. На самом деле я обычно использую настраиваемый макрос assert, который всегда активен.

Время, когда ты будешь @throwсвоим исключение NSException , когда вы определенно хотите его использовать в сборке релиза, и в таких вещах, как публичные библиотеки / интерфейс, когда некоторые аргументы недействительны или вы были вызваны неправильно. Обратите внимание, что это не совсем стандартная практика для @catchисключения и продолжения выполнения вашего приложения. Если вы попробуете это с некоторыми стандартными библиотеками Apple (например, Core Data), могут случиться плохие вещи. Подобно утверждению, если возникает исключение, приложение обычно должно завершаться довольно быстро, потому что это означает, что где-то есть ошибка программирования.

NSErrors следует использовать в ваших библиотеках / интерфейсах для ошибок, которые не являются ошибками программирования и которые можно исправить. Вы можете предоставить вызывающей стороне информацию / коды ошибок, и они смогут аккуратно обработать ошибку, при необходимости предупредить пользователя и продолжить выполнение. Обычно это происходит из-за таких вещей, как ошибка «Файл не найден» или какая-либо другая нефатальная ошибка.

Майк Веллер
источник
15
Если говорить более строго, исключение NSException не должно использоваться для обозначения исправимой ошибки.
bbum
28
Другими словами: NSException Obj-C == Java-класс Error и Obj-C NSError == Java-класс Exception. Ура последовательности в терминах!
Tustin2121 05
2
Фактически, NSAssert будет скомпилирован в ваш код, если вы не добавите NS_BLOCK_ASSERTIONS в свои предварительно скомпилированные файлы префиксов. Прочтите ответ ниже (просто получите 50, чтобы похвалить :)
likid1412
3

Соглашение в Какао состоит в том, что исключение указывает на ошибку программиста. Многие коды, включая код фреймворка, не предназначены для правильной работы после создания исключения.

Любая ошибка, которую необходимо исправить, представлена ​​значком NSError . Также есть система представленияNSError s пользователю. Как вы сказали, это в основном полезно для ошибочных внешних ресурсов.

Концептуально утверждение - это утверждение, что данный предикат всегда оценивается как истинный; если этого не происходит, программа не работает. Хотя его поведение можно изменить, NSAssertсемейство по умолчанию является удобным способом бросания NSInternalInconsistencyExceptions (с возможностью отключения их в сборках выпуска).

Йенс Эйтон
источник
2

Изменить: в Xcode 4.2 утверждения отключены по умолчанию для сборок выпуска,

Теперь NSAssert не будет компилироваться в ваш код в сборке выпуска , но вы можете изменить его в настройках сборки.


@Mike Weller, в вашем ответе есть одна ошибка.

Следует отметить, что NSAssert не будет компилироваться в ваш код в сборке выпуска , поэтому обычно это используется для проверки работоспособности во время разработки.

Фактически, NSAssert будет скомпилирован в ваш код, если вы не добавитеNS_BLOCK_ASSERTIONS свои предварительно скомпилированные файлы префиксов.

В Техническом примечании TN2190 мы можем найти:

Макросы, такие как NDEBUG для отключения C assert или NS_BLOCK_ASSERTIONS для отключения NSAssert Foundation, важно указать для ваших предварительно скомпилированных файлов префиксов.

Или вы можете прочитать это: Как узнать, отключен ли NSAssert в сборках выпуска?

likid1412
источник
1

Как правило, исключения используются для обозначения ошибок программиста - этого не должно происходить. Ошибки используются, чтобы сигнализировать об условиях ошибки, которые могут возникнуть при нормальной работе программы - в основном ошибки пользователя или внешние условия, которые должны быть истинными, но могут не быть. Таким образом, попытка удалить какой-либо заблокированный элемент в документе может быть ошибкой, а попытка загрузить файл без подключения к Интернету будет ошибкой, но попытка получить доступ к недопустимому элементу в коллекции будет исключением.

Утверждения обычно используются при тестировании, а AFAIK не используется в качестве общего механизма обработки ошибок, как другие.

Чак
источник
Утверждения можно использовать для обеспечения инвариантов. Например, NSParameterAssert(someParam != nil);принудительно установит инвариант, что указанный параметр не должен быть нулевым.
Лили Баллард,
@Kevin Ballard: Утверждения обычно определяются вне сборок выпуска, или, по крайней мере, они проверялись в последний раз, поэтому, как я уже сказал, они не являются общим механизмом обработки ошибок.
Чак
1
Они могут быть, но по умолчанию они не опускаются. Вам нужно изменить настройку сборки, чтобы добиться такого поведения.
Лили Баллард,