В чем разница между «предусловием» и «утверждением» в быстром?

105

В чем разница между precondition(condition: Bool, message: String)и assert(condition: Bool, message: String)в Swift?

Мне они оба кажутся одинаковыми. В каком контексте мы должны использовать одно вместо другого?

Чао Жуань
источник

Ответы:

125

assertпредназначен для проверки работоспособности во время тестирования, тогда как он preconditionпредназначен для защиты от вещей, которые, если они произойдут, будут означать, что ваша программа просто не сможет работать.

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

С другой стороны, проверка допустимости нижнего индекса в массиве при выборке элемента - это precondition. При запросе недопустимого нижнего индекса у объекта массива нет разумных следующих действий, поскольку он должен возвращать необязательное значение.

Полный текст из документации (попробуйте щелкнуть опцию assertи preconditionв Xcode):

Предварительное условие

Отметьте необходимое условие для продвижения вперед.

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

  • В игровых площадках и сборках -Onone (по умолчанию для конфигурации отладки Xcode): если conditionзначение равно false, остановить выполнение программы в отлаживаемом состоянии после печати message.

  • В сборках -O (по умолчанию для конфигурации выпуска Xcode): если conditionоценивается как false, остановить выполнение программы.

  • В -Ounchecked строит, conditionне оценивается, но оптимизатор может предположить , что она будет вычисляться true. Несоблюдение этого предположения в сборках -Ounchecked является серьезной ошибкой программирования.

Утверждать

Традиционное утверждение в стиле C с дополнительным сообщением.

Используйте эту функцию для внутренних проверок работоспособности, которые активны во время тестирования, но не влияют на производительность кода доставки. Чтобы проверить недопустимое использование в сборках Release; см precondition.

  • В игровых площадках и сборках -Onone (по умолчанию для конфигурации отладки Xcode): если conditionзначение равно false, остановить выполнение программы в отлаживаемом состоянии после печати message.

  • Сборки In -O (по умолчанию для конфигурации выпуска Xcode) conditionне оцениваются, и нет никаких эффектов.

  • В -Ounchecked строит, conditionне оценивается, но оптимизатор может предположить , что она будет вычисляться true. Несоблюдение этого предположения в сборках -Ounchecked является серьезной ошибкой программирования.

Скорость полета
источник
2
«Но вы бы не хотели поставлять с этим, поскольку результат выхода за пределы может быть действительным и не критичным, поэтому не должно вызывать сбой вашего приложения», это для меня очень расплывчато. Не могли бы вы привести точный пример? Возможно какой-то код.
Дорогая,
2
Отвечая на ваш вопрос, я лично использую утверждения, чтобы отловить то, чего не должно происходить в моей сборке, пока я ее пишу и тестирую. Представьте, что оператор защиты читает JSON там, где data["name"]его нет, но он должен. Наличие утверждения внутри guard..else {} помогло бы мне отловить мою ошибку, сбой и приведя меня к проблеме. Точно так же, если бы этот код был в производстве, assert не привел бы к сбою программы, и любой резервный код, который я использовал ( return nil), взял бы на себя.
Alec O
1
Разве вы не должны проверить индекс и ничего не делать вместо того, чтобы разрушить все приложение?
Юлиан Онофрей
Да, вам следует проверить индекс, но все иногда ошибаются, и использование утверждений помогает вам понять, что вы должны были проверить индекс, когда забыли.
Виктор Энгель
«Но вы бы не хотели поставлять с этим, поскольку результат выхода за пределы может быть действительным и не критичным, поэтому не должно вызывать сбой вашего приложения». Вы можете поставлять свое приложение с любым количеством утверждений. Swift просто не будет оценивать ваши условия внутри блока утверждения в
выпускном
90

Я нашел утверждения Swift - отсутствующее руководство было полезным

                        debug   release   release
function                -Onone  -O       -Ounchecked
assert()                YES     NO        NO
assertionFailure()      YES     NO        NO**
precondition()          YES     YES       NO
preconditionFailure()   YES     YES       YES**
fatalError()*           YES     YES       YES

И из интересных дискуссий о Swift Evolution

- assert: проверка собственного кода на наличие внутренних ошибок

- предварительное условие: для проверки того, что ваши клиенты предоставили вам действительные аргументы.

Кроме того, вы должны быть осторожны с тем, что использовать, см. AssertionFailure и Optimization Level.

onmyway133
источник
Можете ли вы пояснить разницу между собственным кодом и клиентом? Что касается клиента, вы имеете в виду, как вставлять числа там, где ожидается строка? Разве это не следует лечить простой обработкой ошибок?
Дорогая,
@Honey Я думаю, он имеет в виду аргументы / результаты вызова сетевого API или собственных плагинов клиента.
Чен Ли Ён
Клиент - это кто-то, кто использует ваш код, например, вы пишете библиотеку, а программист передает неверные данные. Вы не захотите изящно продолжить, поскольку это можно считать серьезной ошибкой программирования. Вероятно, вы никогда не должны сбой из-за недопустимых данных сетевого API, поскольку это очень бесполезно для пользователя.
bompf
@ onmyway133: От Xcode QuickHelp, я думаю , precondition()и preconditionFailure()которые имеют те же модели поведения . Разница между этими функциями заключается в следующем: preconditionнужно условие внутри, а preconditionFailureпросто выбросить.
nahung89
13

preconditionАктивно в режиме выпуска , так что вы , когда вы отправляете ваше приложение и предварительное условие не удалось приложение завершится. Assertпо умолчанию работает только в режиме отладки.

Я нашел это отличное объяснение, когда использовать его на NSHipster:

Утверждения - это концепция, заимствованная из классической логики. В логике утверждения - это утверждения о предложениях внутри доказательства. В программировании утверждения обозначают предположения, сделанные программистом о приложении в том месте, где они объявлены.

При использовании в качестве предусловий и постусловий, которые описывают ожидания относительно состояния кода в начале и в конце выполнения метода или функции, утверждения образуют контракт. Утверждения также могут использоваться для обеспечения выполнения условий во время выполнения, чтобы предотвратить выполнение, когда определенные предварительные условия не выполняются.

Грег
источник
Утверждения можно включать и отключать с помощью флага компилятора; они могут быть активными в поставляемом коде.
Петур Инги Эгильссон
6

предварительное условие

func precondition(condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = default, file: StaticString = default, line: UWord = default)

Отметьте необходимое условие для продвижения вперед.

  1. Используйте эту функцию для обнаружения условий, которые должны препятствовать работе программы даже в коде доставки.
  2. В игровых площадках и сборках -Onone (по умолчанию для конфигурации отладки Xcode): если условие оценивается как ложное, остановить выполнение программы в отлаживаемом состоянии после печати сообщения.
  3. В сборках -O (по умолчанию для конфигурации выпуска Xcode): если условие оценивается как ложное, остановить выполнение программы.
  4. В сборках -Ounchecked условие не оценивается, но оптимизатор может предположить, что оно будет оцениваться как истинное. Несоблюдение этого предположения в сборках -Ounchecked является серьезной ошибкой программирования.

утверждать

func assert(condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = default, file: StaticString = default, line: UWord = default)

Традиционное утверждение в стиле C с дополнительным сообщением.

  1. Используйте эту функцию для внутренних проверок работоспособности, которые активны во время тестирования, но не влияют на производительность кода доставки. Чтобы проверить недопустимое использование в сборках Release; см. предварительное условие.

  2. В игровых площадках и сборках -Onone (по умолчанию для конфигурации отладки Xcode): если условие оценивается как ложное, остановить выполнение программы в отлаживаемом состоянии после печати сообщения.

  3. В сборках -O (по умолчанию для конфигурации выпуска Xcode) условие не оценивается, и нет никаких эффектов
  4. В сборках -Ounchecked условие не оценивается, но оптимизатор может предположить, что оно будет оцениваться как истинное. Несоблюдение этого предположения в сборках -Ounchecked - серьезная ошибка программирования.
13 призрак
источник
0

Просто хотел добавить свои 2 цента. Вы можете добавить в свой код столько утверждений, сколько захотите. Вы можете отправить свой код с этими утверждениями. Swift НЕ оценивает эти блоки кода для производственных приложений. Они оцениваются только в случае режима отладки.

Добавление ссылки на документацию

Также прикрепляю изображение с swift.org

введите описание изображения здесь

Также обратите внимание, что это не относится к предварительным условиям. Код, поставляемый с предварительными условиями, выйдет из строя, и приложение прекратит работу, если предварительные условия не будут оценены как истинные.

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

И

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

Акшанш Тхакур
источник