Qual é a melhor maneira de lançar uma exceção no objetivo-c / cacau?
objective-c
cocoa
exception-handling
Steph Thirion
fonte
fonte
@throw([NSException exceptionWith…])
abordagem, pois é mais concisa.Uma palavra de cautela aqui. No Objective-C, diferentemente de muitos idiomas semelhantes, você geralmente deve tentar evitar exceções para situações de erro comuns que podem ocorrer em operação normal.
A documentação da Apple para o Obj-C 2.0 afirma o seguinte: "Importante: Exceções consomem muitos recursos no Objective-C. Você não deve usar exceções para controle de fluxo geral ou simplesmente para significar erros (como um arquivo não acessível)"
A documentação conceitual sobre manipulação de exceções da Apple explica o mesmo, mas com mais palavras: "Importante: você deve reservar o uso de exceções para programação ou erros inesperados de tempo de execução, como acesso fora da área de coleta, tentativas de alterar objetos imutáveis, enviando uma mensagem inválida e perdendo a conexão com o servidor de janelas.Você geralmente cuida desses tipos de erros com exceções quando um aplicativo está sendo criado, e não em tempo de execução. [.....] Em vez de exceções, os objetos de erro (NSError) e o O mecanismo de entrega de erros de cacau é a maneira recomendada de comunicar os erros esperados nos aplicativos de cacau. "
As razões para isso são, em parte, aderir aos idiomas de programação no Objective-C (usando valores de retorno em casos simples e parâmetros por referência (geralmente a classe NSError) em casos mais complexos), em parte que lançar e capturar exceções é muito mais caro e finalmente (e é mais importante ainda) que as exceções de Objective-C são um invólucro fino em torno das funções setjmp () e longjmp () de C, essencialmente atrapalhando seu tratamento cuidadoso da memória, consulte esta explicação .
fonte
O Xcode reconhece
@throw
instruções como pontos de saída da função, comoreturn
instruções. O uso da@throw
sintaxe evita avisos errôneos de "O controle pode chegar ao fim da função não nula " que você pode obter[NSException raise:…]
.Além disso,
@throw
pode ser usado para lançar objetos que não são da classe NSException.fonte
Em relação
[NSException raise:format:]
. Para quem vem de um plano de fundo Java, você deve se lembrar que Java distingue entre Exception e RuntimeException. Exceção é uma exceção verificada e RuntimeException está desmarcada. Em particular, Java sugere o uso de exceções verificadas para "condições normais de erro" e exceções não verificadas para "erros de tempo de execução causados por um erro do programador". Parece que as exceções de Objective-C devem ser usadas nos mesmos locais em que você usaria uma exceção desmarcada, e os valores de retorno do código de erro ou NSError são preferidos nos locais em que você usaria uma exceção verificada.fonte
Eu acho que para ser consistente, é melhor usar o @throw com sua própria classe que estende o NSException. Então você usa as mesmas notações para finalmente tentar pegar:
A Apple explica aqui como lançar e manipular exceções: Capturando exceções Lançando exceções
fonte
Desde o ObjC 2.0, as exceções Objective-C não são mais um invólucro para setjmp () longjmp () e são compatíveis com a exceção C ++, o @try é "gratuito", mas lançar e capturar exceções é muito mais caro.
De qualquer forma, as asserções (usando a família de macro NSAssert e NSCAssert) geram NSException, e é sensato usá-las como estados Ries.
fonte
Use o NSError para comunicar falhas em vez de exceções.
Pontos rápidos sobre o NSError:
O NSError permite que códigos de erro no estilo C (números inteiros) identifiquem claramente a causa raiz e esperemos que permita que o manipulador de erros supere o erro. É possível agrupar códigos de erro de bibliotecas C como SQLite em instâncias do NSError com muita facilidade.
O NSError também tem o benefício de ser um objeto e oferece uma maneira de descrever o erro em mais detalhes com seu membro do dicionário userInfo.
Mas o melhor de tudo é que o NSError NÃO PODE ser lançado, por isso encoraja uma abordagem mais proativa ao tratamento de erros, em contraste com outros idiomas que simplesmente jogam a batata quente mais longe e aumentam a pilha de chamadas, momento em que ela só pode ser relatada ao usuário e não tratado de maneira significativa (não se você acredita em seguir o maior princípio de ocultação de informações da OOP).
Link de referência : Referência
fonte
Foi assim que aprendi no "The Big Nerd Ranch Guide (4th edition)":
fonte
userInfo:nil
. :)Você pode usar dois métodos para gerar exceção no bloco try catch
ou o segundo método
fonte
Eu acredito que você nunca deve usar exceções para controlar o fluxo normal do programa. Porém, exceções devem ser lançadas sempre que algum valor não corresponder ao valor desejado.
Por exemplo, se alguma função aceita um valor, e esse valor nunca pode ser nulo, então é bom lançar uma exceção em vez de tentar fazer algo 'inteligente' ...
Ries
fonte
Você só deve lançar exceções se se encontrar em uma situação que indica um erro de programação e desejar interromper a execução do aplicativo. Portanto, a melhor maneira de lançar exceções é usar as macros NSAssert e NSParameterAssert e garantir que NS_BLOCK_ASSERTIONS não esteja definido.
fonte
Código de exemplo para case: @throw ([NSException exceptionWithName: ...
}
Usando:
Outro caso de uso mais avançado:
}
fonte
Não há razão para não usar exceções normalmente no objetivo C, mesmo para significar exceções de regras de negócios. A Apple pode dizer que use o NSError quem se importa. O Obj C existe há muito tempo e, ao mesmo tempo, TODA a documentação do C ++ dizia a mesma coisa. A razão pela qual não importa o quão caro lançar e capturar uma exceção é, é o tempo de vida de uma exceção é extremamente curto e ... é uma EXCEÇÃO ao fluxo normal. Eu nunca ouvi alguém dizer alguma vez na minha vida, cara essa exceção demorou muito tempo para ser jogada e pega.
Além disso, existem pessoas que acham que o objetivo C em si é muito caro e, em vez disso, codificam em C ou C ++. Dizer que sempre usar NSError é mal informado e paranóico.
Mas a questão dessa discussão ainda não foi respondida, qual é a MELHOR maneira de lançar uma exceção. As maneiras de retornar o NSError são óbvias.
Assim é: [NSException raise: ... @throw [[NSException aloc] initWithName .... ou @throw [[MyCustomException ...?
Eu uso a regra marcada / desmarcada aqui de maneira um pouco diferente da anterior.
A diferença real entre a (usando a metáfora java aqui) marcada / desmarcada é importante -> se você pode se recuperar da exceção. E por recuperação, quero dizer não apenas não travar.
Então, eu uso classes de exceção personalizadas com @throw para exceções recuperáveis, porque é provável que eu tenha algum método de aplicativo procurando por certos tipos de falhas em vários blocos @catch. Por exemplo, se meu aplicativo for um caixa eletrônico, eu teria um bloco @catch para a "WithdrawalRequestExceedsBalanceException".
Eu uso o NSException: raise para exceções de tempo de execução, pois não tenho como me recuperar da exceção, exceto para capturá-la em um nível superior e registrá-la. E não faz sentido criar uma classe personalizada para isso.
Enfim, é isso que eu faço, mas se houver uma maneira melhor e igualmente expressiva, eu gostaria de saber também. No meu próprio código, desde que parei de codificar C há muito tempo, nunca retornei um NSError, mesmo que eu tenha passado um por uma API.
fonte