Является ли утверждение, что каждое создание объекта успешно выполнено в Задаче C? - PullRequest
4 голосов
/ 27 марта 2011

Я недавно прочитал пример кода Apple для MVCNetworking , написанный гуру технической поддержки разработчиков Apple Квинн "Эскимос!"Образец - действительно хороший опыт обучения с лучшими практиками разработки для iOS.Что меня удивило, исходя из языков JVM, так это чрезвычайно частые утверждения:

syncDate = [NSDate date];
assert(syncDate != nil);

и это:

photosToRemove = [NSMutableSet setWithArray:knownPhotos];
assert(photosToRemove != nil);

и это:

photoIDToKnownPhotos = [NSMutableDictionary dictionary];
assert(photoIDToKnownPhotos != nil);

что действительно нужно?Стоит ли подражать этому стилю кодирования?

Ответы [ 5 ]

4 голосов
/ 27 марта 2011

Если вы привыкли к Java, это может показаться странным. Вы ожидаете, что сообщение о создании объекта вызовет исключение при сбое, а не вернет nil. Однако, хотя Objective-C в Mac OS X имеет поддержку обработки исключений ; это дополнительная функция, которую можно включить / выключить с помощью флага компилятора. Стандартные библиотеки написаны так, что их можно использовать без включенной обработки исключений: поэтому сообщения часто возвращают nil, чтобы указать на ошибки, а иногда требуют, чтобы вы также передали указатель на переменную NSError*. (Это для разработки на Mac, я не уверен, сможете ли вы даже включить поддержку обработки исключений для iOS, учитывая, что вы также не можете включить сборку мусора для iOS.)

В разделе «Обработка ошибок инициализации» в документе «Язык программирования Objective-C» объясняется, как программисты Objective-C должны исправлять ошибки при инициализации / создании объекта: то есть возвращать nil.

Что-то вроде [NSData dataWithContentsOfFile: path] может определенно возвращать nil: документация по методу прямо говорит об этом. Но я, честно говоря, не уверен, вернется ли когда-нибудь что-то вроде [NSMutableArray arrayWithCapacity: n] nil. Единственная ситуация, которую я могу вспомнить, когда может , - это когда у приложения недостаточно памяти. Но в этом случае я ожидаю, что приложение будет прервано при попытке выделить больше памяти. Я не проверял это, хотя, и вполне может быть, что он возвращает nil в этом случае. Хотя в Objective-C вы часто можете безопасно отправлять сообщения на nil, это может привести к нежелательным результатам. Например, ваше приложение может попытаться создать NSMutableArray, получить вместо него nil, а затем успешно продолжить отправку addObject: в nil и записать пустой файл на диск, а не файл с элементами массива, как предполагалось , Поэтому в некоторых случаях лучше явно проверить, был ли результат сообщения nil. Нужно ли делать это в каждом создании объекта, как это делает программист, которого вы цитируете, я не уверен. Лучше быть в безопасности, чем потом сожалеть?

Редактировать: Я бы хотел добавить, что хотя проверка успешности создания объекта иногда может быть хорошей идеей, утверждение может быть не лучшим идея. Вы бы хотели, чтобы это также проверялось в выпускной версии вашего приложения, а не только в отладочной версии. В противном случае это как бы лишает смысла проверять его, поскольку вы не хотите, чтобы конечный пользователь приложения, например, запустил пустые файлы, потому что [NSMutableArray arrayWithCapacity: n] вернул nil, и приложение продолжало отправлять сообщения на nil возвращаемое значение Утверждения (с assert или NSAssert) могут быть удалены из версии выпуска с флагами компилятора; Xcode, по-видимому, по умолчанию не включает эти флаги в конфигурацию «Release». Но если вы захотите использовать эти флаги для удаления некоторых других утверждений, вы также удалите все проверки «Создание объекта успешно завершено».

Редактировать: После дальнейших размышлений кажется более правдоподобным, чем я думал, что [NSMutableArray arrayWithCapacity: n] вернет nil, а не прервет приложение, если недостаточно памяти. Basic C malloc также не прерывается, но возвращает указатель NULL, когда недостаточно памяти. Но я еще не нашел четкого упоминания об этом в документации Objective-C по alloc и аналогичным методам.

Редактировать: Выше я сказал, что не уверен, что проверка nil необходима при каждом создании объекта.Но так не должно быть.Именно поэтому Objective-C позволяет отправлять сообщения на nil, которые затем возвращают nil (или 0 или что-то подобное, в зависимости от определения сообщения): таким образом, nil может распространяться через ваш код, несколько похожийисключение, чтобы не приходилось явно проверять наличие nil в каждом отдельном сообщении, которое может его вернуть.Но рекомендуется проверять его в тех местах, где вы не хотите, чтобы он распространялся, например, при записи файлов, взаимодействии с пользователем и т. Д. Или в случаях, когда результат отправки сообщения на nil не определен(как объяснено в документации по отправке сообщений на nil).Я был бы склонен сказать, что это похоже на версию распространения и обработки исключений для «бедняков», хотя не все могут согласиться с тем, что последнее лучше;но nil ничего не говорит вам о том, почему произошла ошибка, и вы можете легко забыть проверить ее там, где такие проверки необходимы.

3 голосов
/ 27 марта 2011

Предлагаем вам прочитать эту статью на Защитное программирование

2 голосов
/ 27 марта 2011

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

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

2 голосов
/ 27 марта 2011

Да. Я думаю, что это хорошая идея. Это помогает отфильтровать крайние случаи (нехватка памяти, входные переменные пустые / ноль), как только переменные введены. Хотя я не уверен, что влияние на скорость из-за накладных расходов!

1 голос
/ 28 марта 2011

У меня также спрашивал об этом на Apple DevForums . По словам Куинна "Эскимос!" (автор рассматриваемого примера MVCNetworking) это вопрос стиля кодирования и его личных предпочтений :

Я использую много утверждений, потому что ненавижу отладку. (...)

Имейте в виду, что я вырос на традиционной Mac OS, где один мошеннический указатель мог сломать всю вашу машину (аналогично программированию ядра в современных системах). В этом мире было важно найти ваши ошибки раньше, чем позже . И многие утверждают, помогают вы делаете это.

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

Тем не менее, я думаю, что у вас есть верная точка зрения с такими вещами, как +[NSDate date]. Шансы на это возвращение ноль невелики. Утверждение существует чисто по привычке . Но я думаю, что стоимость этой привычки (некоторая дополнительная печать, учащаяся игнорировать утверждения) мала по сравнению с выгодами.

Из этого я заключаю, что утверждение о том, что создание каждого объекта прошло успешно, не является строго необходимым.

  • Утверждения могут быть полезны для документирования предварительных условий в методах, в процессе разработки, в качестве вспомогательного средства проектирования для других сопровождающих (включая будущее Я). Лично я предпочитаю альтернативный стиль - разделять спецификацию и реализацию, используя методы TDD / BDD.

  • Утверждения могут использоваться для двойной проверки типов времени выполнения аргументов метода из-за динамической природы Objective C:

    assert([response isKindOfClass:[NSHTTPURLResponse class]]);
    

Я уверен, что есть более хорошие применения утверждений. Все вещи умеренные ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...