Какой смысл в NSAssert, на самом деле?

155

Я должен спросить это, потому что: Единственное, что я узнаю, это то, что, если утверждение не выполняется, приложение падает. Это причина, почему использовать NSAssert? Или какая еще польза от этого? И правильно ли ставить NSAssert чуть выше любого предположения, которое я делаю в коде, например, функцию, которая никогда не получит -1 в качестве параметра, но может быть -0,9 или -1,1?

TheNeil
источник

Ответы:

300

Утверждать, чтобы убедиться, что значение является то, что он должен быть. Если утверждение не выполняется, это означает, что что-то пошло не так, и приложение закрывается. Одной из причин использования assert может быть то, что если у вас есть какая-то функция, которая не будет работать или создаст очень плохие побочные эффекты, если один из переданных ей параметров не совсем какое-то значение (или диапазон значений), вы можете поместить assert, чтобы сделать убедитесь, что это то, что вы ожидаете, и если это не так, то что-то действительно не так, и приложение закрывается. Assert может быть очень полезным для отладки / юнит-тестирования, а также когда вы предоставляете фреймворки, чтобы пользователи не делали «злых» дел.

Даниил
источник
9
Вы должны взять NSAssert для выпуска. Для этого есть флаг времени компиляции.
Барри Уорк
127
> Вы должны вынуть NSAssert для выпуска. Это спорно. Я всегда выпускаю свои приложения с включенными утверждениями, и это стандартная практика для многих программ, например, Apple это делает. Как только ваша программа обнаружит ненормальное состояние, вы должны аварийно завершить работу. Вы можете получить трассировку стека, где произошла ошибка, тогда как, если вы отключите утверждения, вы можете повредить память и / или пользовательские данные, и проблему будет очень трудно отладить.
Майк Веллер
18
Обратите внимание, что XCode 4 имеет NS_BLOCK_ASSERTIONS, определенный по умолчанию в конфигурациях выпуска. Я думаю, если вы не измените, что ваш выпущенный код не будет содержать NSAssert: s.
Джонни
16
Если я правильно понимаю, какой смысл их оставлять (в релизной версии)? Почему бы не заменить NSAssert на оператор if, и если (что-то ужасное случается), то проинформируйте пользователя (или сделайте что-то, что находится под вашим контролем), а не просто выйдите из системы / произойдет сбой и оставьте пользователя интересующимся, что случилось ... Или я что-то упускаю?
Гик
11
Разработчик тратит время на то, чтобы идти по пути каждого исключительного случая, который не должен происходить вообще при нормальных обстоятельствах. Это включает в себя продумывание подходящих способов информирования пользователя о каждом из них и / или создание приложения, достаточно надежного, чтобы оно могло продолжаться ожидаемым образом после их появления. Более практичным подходом является сбой приложения, исправление ошибки, обнаруженной в отчете о сбое, и выпуск новой версии. Сказав это, важно убедиться, что в любой такой ситуации нет потери данных. Тем не менее, это должно быть обеспечено, но это гораздо меньшая работа.
trss
20

Я не могу говорить с NSAssert, но я представляю, что он работает аналогично assert () в C.

assert () используется для обеспечения семантического контракта в вашем коде. Вы спросите, что это значит?

Что ж, это как вы сказали: если у вас есть функция, которая никогда не должна получать -1, вы можете использовать assert (), чтобы:

void gimme_positive_ints (int i) {
  утверждать (я> 0);
}

И теперь вы увидите что-то вроде этого в журнале ошибок (или STDERR):

Утверждение i> 0 не выполнено: файл example.c, строка 2

Таким образом, он не только защищает от потенциально плохих входных данных, но и регистрирует их полезным, стандартным способом.

Да, и по крайней мере в C assert () был макрос, так что вы можете переопределить assert () как запрет на использование в вашем коде релиза. Я не знаю, так ли это с NSAssert (или даже с assert ()), но было довольно полезно скомпилировать эти проверки.

Mando Escamilla
источник
2
Да, NSAssert также является макросом.
Мартин Уикман,
18

NSAssertдает вам больше, чем просто сбой приложения. Он сообщает вам класс, метод и строку, где произошло утверждение. Все утверждения также могут быть легко деактивированы с помощью NS_BLOCK_ASSERTIONS. Таким образом, делая его более подходящим для отладки. С другой стороны, выбрасывание приложения приводит к NSExceptionсбою приложения. Это также не говорит о местонахождении исключения, и при этом это не может быть отключено так просто. Смотрите разницу в изображениях ниже.

Приложение падает, потому что утверждение также вызывает исключение, как указано в документации NSAssert :

При вызове обработчик утверждений печатает сообщение об ошибке, которое включает имена методов и классов (или имя функции). Затем он вызывает исключение NSInternalInconsistencyException.

NSAssert:

Логи после утверждения

NSException:

Журналы после исключения

Абдуррахман Мубин Али
источник
NSExceptionПредоставляет множество возможностей для настройки выходного сигнала он возвращается по reasonи userInfoпараметрам. Нет причин, по которым вы не можете добавить имя класса, селектор, информацию о строке и все, что вы хотите добавить, чтобы помочь в отладке. ИМХО, вы используете NSAssertдля целей отладки во время разработки, но отключаете их для отправки; Вы бросаете, NSExceptionесли хотите оставить в утверждении в коде доставки.
Markeissler
17

Помимо того, что все говорили выше, стандартное поведение NSAssert()(в отличие от C assert()) - генерировать исключение, которое вы можете перехватить и обработать. Например, Xcode делает это.

Дженс Айтон
источник
Есть ли еще что-то о том, как мы можем поймать и обработать исключение?
Гон
1
Исключения в какао не являются «ловимыми и управляемыми» де-факто. Если управление проходит через функцию apple в любом месте дерева вызовов, поведение не определено. Исключения только для сообщений об ошибках (иначе, критерицизм и т. Д.), А не для общего использования, как в Java.
Майкл
9

Просто чтобы прояснить, как кто-то упомянул, но не полностью объяснил, причина наличия и использования утверждений вместо простого создания пользовательского кода (например, выполнение if и повышение исключения для неверных данных) состоит в том, что утверждения СЛЕДУЕТ отключать для производственных приложений.

Во время разработки и отладки вы можете отслеживать ошибки. Программа остановится, когда утверждение будет оценено как ложное. Но при компиляции для производства компилятор пропускает код подтверждения и фактически делает вашу программу запущенной быстрее. К тому времени, надеюсь, вы исправили все ошибки. Если ваша программа все еще имеет ошибки во время работы (когда утверждения отключены и программа «пропускает» утверждения), ваша программа, вероятно, завершится сбоем в какой-то другой точке.

Из справки NSAssert: «Утверждения отключены, если определен макрос препроцессора NS_BLOCK_ASSERTIONS». Итак, просто поместите макрос в вашу цель распространения [только].

Охад Кравчик
источник
6

NSAssert(и его эквивалент stdlib assert) предназначены для обнаружения ошибок программирования во время разработки. Вы никогда не должны иметь утверждение, которое терпит неудачу в производственном (выпущенном) приложении. Таким образом, вы можете утверждать, что никогда не передаете отрицательное число методу, который требует положительного аргумента. Если утверждение когда-либо не выполняется во время тестирования, у вас есть ошибка. Однако, если переданное значение вводится пользователем, вам необходимо выполнить правильную проверку входных данных, а не полагаться на утверждение в работе (вы можете установить #define для сборок релизов, которые отключают NSAssert*.

Барри Уарк
источник
2
+1, потому что твой ответ имеет наибольшее значение для меня! Использование NSAssert имеет больше смысла, если его для разработки использовать, а не после выпуска. Пользователь, вводящий недопустимое значение, должен сопровождаться ошибкой пользовательского интерфейса, а не NSAssert, вызывающим сбой приложения. Туман рассеялся!
pnizzle
3

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

Краткий ответ: они обеспечивают использование вашего кода только по назначению.

Залы ожидания
источник
3

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

Более подробную информацию о предмете утверждения и дизайна по контракту можно найти ниже:

Утверждение (разработка программного обеспечения)

Дизайн по контракту

Программирование с утверждениями

Дизайн по контракту, по примеру [Мягкая обложка]

благодеяние
источник
2

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

Например, вы можете передать значение функции, ожидающей значения в определенном диапазоне. Функция может сохранить значение для последующего использования, а при последующем использовании происходит сбой приложения. Стек вызовов, видимый в этом сценарии, не будет показывать источник неверного значения. Лучше поймать плохое значение, когда оно приходит, чтобы узнать, кто передает плохое значение и почему.

Роберт Хоки
источник
-3

NSAssertсделать сбой приложения, когда оно соответствует условию. Если не совпадают с условием, будут выполнены следующие операторы. Посмотрите на EX ниже:

Я просто создаю приложение, чтобы проверить, что является задачей NSAssert:

    - (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self testingFunction:2];
}

-(void)testingFunction: (int)anNum{
    // if anNum < 2 -> the app will crash
    // and the NSLog statement will not execute
    // that mean you cannot see the string: "This statement will execute when anNum < 2"
    // into the log console window of Xcode
    NSAssert(anNum >= 2, @"number you enter less than 2");
    // If anNum >= 2 -> the app will not crash and the below 
    // statement will execute
    NSLog(@"This statement will execute when anNum < 2");
}

в моем коде приложение не будет аварийно завершено. И контрольный пример:

  • anNum > = 2 -> Приложение не завершится сбоем, и вы увидите строку журнала: «Этот оператор будет выполняться при anNum <2» в окне консоли журнала outPut
  • anNum <2 -> Приложение аварийно завершает работу, и вы не видите строку журнала: «Этот оператор будет выполняться, когда anNum <2»

источник
1
Вы получили это наоборот. Msgstr "NSAssert вызывает сбой приложения, когда оно соответствует условию. Если не соответствует условию, будут выполнены следующие операторы". NSAssert завершает работу приложения, если оно НЕ соответствует условию, и выполняется нормально, если оно НЕ соответствует условию.
Джо Там
Приложение вылетает и регистрирует сообщение, когда оно не соответствует условию, в противном случае оно выполняется дальше.
Правин С.