При переносе кода Java в ObjC, как лучше всего представлять проверенные исключения? - PullRequest
8 голосов
/ 13 июля 2009

Я работаю над переносом кодовой базы Java на Cocoa / Objective-C для использования на настольных компьютерах Mac OS X. Код Java имеет лоты и лоты методов с проверенными исключениями, такими как :

double asNumber() throws FooException {
    ...
}

Как лучше всего представить их в Objective-C? Исключения или выходные параметры ошибки?

- (CGFloat)asNumber { 
    ... // possibly [FooException raise:format:];
}

или

- (CGFloat)asNumberError:(NSError **)outError {
    ...
}

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

Конечно, имейте в виду, что, поскольку в Java это проверенные исключения, мне нужно будет добавить либо @try блоков, либо if (*outError) {...} проверок, где бы эти методы ни вызывались ( лотов мест).

Я помню, как слышал, что вход в блоки @try когда-то был дорогим в Objective-C, но дешев в 64-битном или SL-режиме или в какой-то другой новой среде (не помню точно). Меня совсем не беспокоит обратная совместимость, поэтому я определенно желаю проектировать только для новой жаркости.

Ответы [ 6 ]

16 голосов
/ 13 июля 2009

Вы должны определенно избегать исключений для таких вещей, как разбор чисел из строк. В Objective-C исключения представляют ошибку программиста, а не ошибку ввода пользователя или даже недоступные файлы. (Частично причина в том, что обработка исключений всегда более затратна и сложна, чем более «обычная» обработка ошибок. Независимо от того, что ввод блоков @try равен «нулевой стоимости» в 64-битном , это все еще медленный всякий раз, когда возникает исключение.) Конечно, вы можете использовать исключения по своему усмотрению, но это не способ Какао, и вы окажетесь в противоречии с другим кодом Objective-C. Люди, которые используют ваш код, будут невероятно раздражены тем, что вы генерируете исключения в случаях, которые могут привести к ошибке.

Из Документы Apple :

"Во многих средах использование исключений является довольно распространенным явлением. Например, вы можете выдать исключение, чтобы указать, что подпрограмма не может выполняться нормально - например, когда файл отсутствует или данные не могут быть проанализированы правильно Исключения являются ресурсоемкими в Objective C. Вы не должны использовать исключения для общего управления потоком или просто для обозначения ошибок. Вместо этого вы должны использовать возвращаемое значение метода или функции, чтобы указать, что произошла ошибка, и предоставить информация о проблеме в объекте ошибки. "

Посмотрите, как встроенные классы Какао обрабатывают подобные ошибки. Например, NSString имеет такие методы, как -floatValue, которые возвращают 0 в случае сбоя. Лучшим решением для вашей конкретной ситуации может быть то, как NSScanner делает это, например, -scanFloat: - принимает указатель на поле, в котором должен быть сохранен результат, и возвращает YES или NO на основе о том, был ли анализ успешным.

Помимо соглашения и передового опыта Obejctive-C, NSError гораздо более надежен и гибок, чем NSException, и позволяет вызывающей стороне эффективно игнорировать проблему, если они этого хотят. Я предлагаю прочитать Руководство по программированию обработки ошибок для какао . Примечание: Если вы принимаете параметр NSError**, я настоятельно рекомендую вам также разрешить клиенту передавать NULL, если он не хочет получать какую-либо информацию об ошибке. Каждый известный мне класс Какао делает это из-за ошибок, включая NSString.

Хотя портированный код может в конечном итоге выглядеть совсем не так, как Java-код, следует понимать, что он будет использоваться кодом Objective C, а не теми же клиентами, что и Java-эквивалент. Определенно соответствует идиомы языка. Порт не будет зеркальным отображением кода Java, но в результате он будет намного более корректным (для Objective-C).

7 голосов
/ 13 июля 2009

В Какао исключения действительно должны использоваться только для "ошибок программирования"; философия заключается в том, чтобы приложение могло их поймать, дать пользователю возможность сохранить то, что они делают, и выйти. С одной стороны, не все фреймворки или пути кода могут быть на 100% безопасными для исключений, поэтому это может быть единственным безопасным способом действий. Для ошибок, которые можно предвидеть и исправить, следует использовать NSError, как правило, через выходной параметр.

3 голосов
/ 13 июля 2009

Вы правы, что "ошибки, как правило, являются лучшим решением для ObjC". Очень редко вы найдете API в Какао, который выдает исключение (если вы не выполнили предварительные условия для API, но в этом случае поведение по умолчанию не определено).

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

2 голосов
/ 13 июля 2009

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

2 голосов
/ 13 июля 2009

Я большой поклонник подхода Out Error, который использует Objective-C. Вы должны обрабатывать исключения, но вы можете игнорировать ошибки, если хотите. Все это соответствует взгляду Objective-C на то, что «программист знает, что делает». Это также делает Objective-C очень чистым языком, потому что ваш код не загроможден блоками try-catch.

При этом вы можете подумать: есть ли сценарии, в которых исключения игнорируются? Являются ли исключения, которые вы выбрасываете, действительно критическими ? Вы пишете простые блоки catch, которые очищают переменные и продолжают работу? Я склоняюсь к ошибкам, потому что мне нравятся исключения из синтаксиса и резервов Objective C только для самых критических ошибок.

0 голосов
/ 13 июля 2009

Исключения, вероятно, являются лучшим подходом, так как 64-разрядный ABI Obj-C (среда выполнения) использует исключения с нулевой стоимостью, так что вы получите более чистый код без реальной стоимости. Конечно, в 32-битных версиях старые исключения setjmp / longjmp все еще используются, и они не взаимодействуют с C ++, поэтому, если это цель, у вас есть проблема.

...