Qual é o sentido do NSAssert, na verdade?

155

Eu tenho que perguntar isso porque: A única coisa que reconheço é que, se a afirmação falhar, o aplicativo trava. É por isso que usar o NSAssert? Ou qual é o benefício disso? E é correto colocar um NSAssert acima de qualquer suposição que eu faça no código, como uma função que nunca deve receber um -1 como parâmetro, mas pode -0,9 ou -1,1?

TheNeil
fonte

Respostas:

300

Afirmar é garantir que um valor seja o que deveria ser. Se uma afirmação falhar, isso significa que algo deu errado e o aplicativo é encerrado. Uma razão para usar assert seria se você tiver alguma função que não se comportará ou criará efeitos colaterais muito ruins se um dos parâmetros passados ​​para ele não for exatamente algum valor (ou um intervalo de valores), você pode colocar uma afirmação para fazer verifique se esse valor é o que você espera que seja e, se não for, algo está realmente errado e o aplicativo será encerrado. A declaração pode ser muito útil para depuração / teste de unidade e também quando você fornece estruturas para impedir que os usuários façam coisas "más".

Daniel
fonte
9
Você deve remover o NSAssert para lançamento. Há um sinalizador em tempo de compilação para fazer isso.
Barry Wark
127
> Você deve retirar o NSAssert para lançamento. Isso é discutível. Sempre libero meus aplicativos com asserções ativadas, e essa é uma prática padrão para muitos softwares, como a Apple, por exemplo. Assim que seu programa detectar um estado anormal, você deverá travar. Você pode obter um rastreamento de pilha de onde ocorreu o erro, enquanto que se você desabilitar as afirmações, poderá acabar corrompendo a memória e / ou os dados do usuário, e o problema será muito difícil de depurar.
Mike Weller
18
Observe que o XCode 4 possui NS_BLOCK_ASSERTIONS definido por padrão nas configurações de liberação. Acho que se você não alterar, o código liberado não conterá NSAssert: s.
Jonny
16
Se bem entendi, qual é o sentido de deixá-los (na versão de lançamento)? Por que não substituir o NSAssert por uma instrução if, e se (algo terrível acontecer), informe o usuário (ou faça algo que está sob seu controle) e não apenas saia / trava e deixe o usuário se perguntando o que aconteceu ... Ou estou esquecendo de algo?
Gik 27/12 /
11
É uma perda de tempo do desenvolvedor seguir o caminho de todos os casos excepcionais que não deveriam acontecer em circunstâncias normais. Isso envolve pensar em maneiras apropriadas de informar o usuário para cada um deles e / ou tornar o aplicativo robusto o suficiente para continuar da maneira esperada após a ocorrência. A abordagem mais prática é travar o aplicativo e corrigir o bug encontrado no relatório de falhas e lançar uma nova versão. Dito isto, é importante garantir que não haja perda de dados em nenhuma dessas situações. No entanto, isso deve ser garantido, mas é um trabalho muito menor.
trss 30/05
20

Eu realmente não posso falar com a NSAssert, mas imagino que funcione de maneira semelhante à afirmação de C ().

assert () é usado para impor um contrato semântico no seu código. O que significa isso, você pergunta?

Bem, é como você disse: se você tem uma função que nunca deve receber um -1, pode ter o assert () que impõe isso:

void gimme_positive_ints (int i) {
  afirmar (i> 0);
}

E agora você verá algo assim no log de erros (ou STDERR):

Falha na asserção i> 0: arquivo example.c, linha 2

Portanto, ele não apenas protege contra entradas potencialmente ruins, como as registra de maneira útil e padrão.

Ah, e pelo menos em C assert () havia uma macro, para que você pudesse redefinir assert () como não operacional no seu código de lançamento. Não sei se esse é o caso do NSAssert (ou até mesmo assert ()), mas foi bastante útil compilar essas verificações.

Mando Escamilla
fonte
2
Sim, NSAssert também é uma macro.
Martin Wickman
18

NSAssertoferece mais do que apenas travar o aplicativo. Indica a classe, o método e a linha em que a afirmação ocorreu. Todas as asserções também podem ser facilmente desativadas usando NS_BLOCK_ASSERTIONS. Assim, tornando-o mais adequado para depuração. Por outro lado, jogar um NSExceptionúnico trava o aplicativo. Ele também não informa sobre a localização da exceção, nem pode ser desativado de maneira simples. Veja a diferença nas imagens abaixo.

O aplicativo falha porque uma asserção também gera uma exceção, conforme a documentação da NSAssert afirma:

Quando invocado, um manipulador de asserções imprime uma mensagem de erro que inclui os nomes de métodos e classes (ou o nome da função). Em seguida, gera uma exceção NSInternalInconsistencyException.

NSAssert:

Registra após uma asserção

NSException:

Registra após uma exceção

Abdurrahman Mubeen Ali
fonte
Um NSExceptionfornece muitas oportunidades para personalizar a saída que retorna através dos parâmetros reasone userInfo. Não há motivo para você não poder adicionar o nome da classe, o seletor, as informações da linha e qualquer outra coisa que queira adicionar para ajudar na depuração. IMHO, você usa um NSAssertpara fins de depuração durante o desenvolvimento, mas os desabilita para enviar; você lança um NSExceptionse quiser deixar uma afirmação no código de remessa.
Markeissler 27/08/2015
17

Além do que todos disseram acima, o comportamento padrão de NSAssert()(ao contrário dos C's assert()) é lançar uma exceção que você pode capturar e manipular. Por exemplo, o Xcode faz isso.

Jens Ayton
fonte
Existe mais sobre como podemos capturar e lidar com a exceção?
24413 Gon
1
Exceções no cacau NÃO são "capturáveis ​​e manipuláveis" de fato. Se o controle passar por uma função da apple em qualquer lugar da árvore de chamadas, o comportamento será indefinido. As exceções são puramente para relatórios de erros (aka, crittercism, etc), não para uso geral, como em Java.
Michael Michael
9

Apenas para esclarecer, como alguém mencionado, mas não totalmente explicado, a razão para ter e usar afirmações em vez de apenas criar código personalizado (fazendo ifs e criando uma exceção para dados ruins, por exemplo) é que afirma que DEVE ser desativado para aplicativos de produção.

Durante o desenvolvimento e a depuração, as declarações são ativadas para você detectar erros. O programa será interrompido quando uma declaração for avaliada como falsa. Porém, ao compilar para produção, o compilador omite o código de asserção e, na verdade, REALIZE SEU PROGRAMA MAIS RÁPIDO. Até então, espero que você tenha corrigido todos os erros. Caso seu programa ainda tenha erros durante a produção (quando as asserções estão desabilitadas e o programa "pula" as asserções)), é provável que seu programa acabe travando em algum outro momento.

Da ajuda do NSAssert: "As asserções serão desabilitadas se a macro NS_BLOCK_ASSERTIONS do pré-processador estiver definida." Então, basta colocar a macro no seu destino de distribuição [apenas].

Ohad Kravchick
fonte
6

NSAssert(e seu equivalente stdlib assert) são para detectar erros de programação durante o desenvolvimento. Você nunca deve ter uma asserção que falha em um aplicativo de produção (liberado). Portanto, você pode afirmar que nunca passa um número negativo para um método que requer um argumento positivo. Se a afirmação falhar durante o teste, você tem um erro. Se, no entanto, o valor passado for inserido pelo usuário, você precisará fazer a validação adequada da entrada, em vez de confiar na asserção em produção (você pode definir um #define para builds de release que desabilita NSAssert*.

Barry Wark
fonte
2
+1 porque sua resposta faz mais sentido para mim! O uso do NSAssert faz mais sentido se for para uso em desenvolvimento, não após o lançamento. Um usuário digitando um valor que não é permitido deve ser seguido por um erro de interface do usuário, e não por NSAssert travando o aplicativo. O nevoeiro desapareceu!
Pnizzle
3

As asserções são comumente usadas para impor o uso pretendido de um método ou pedaço de lógica específico. Digamos que você estivesse escrevendo um método que calcula a soma de dois maiores que zero números inteiros. Para garantir que o método sempre fosse usado como pretendido, você provavelmente colocaria uma afirmação que testa essa condição.

Resposta curta: eles reforçam que seu código é usado apenas como pretendido.

Lounges
fonte
2

Para responder completamente à sua pergunta, o objetivo de qualquer tipo de afirmação é ajudar na depuração. É mais valioso capturar erros na origem e capturá-los no depurador quando eles causam falhas.

Por exemplo, você pode passar um valor para uma função que espera valores em um determinado intervalo. A função pode armazenar o valor para uso posterior e, posteriormente, o aplicativo trava. A pilha de chamadas vista neste cenário não mostraria a origem do valor incorreto. É melhor pegar o valor ruim, pois ele chega para descobrir quem está passando o valor ruim e por quê.

Robert Hawkey
fonte
-3

NSAssertfaça com que o aplicativo falhe quando corresponder à condição. Se não corresponder à condição, as próximas instruções serão executadas. Procure o EX abaixo:

Acabei de criar um aplicativo para testar qual é a tarefa 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");
}

no meu código, o aplicativo não trava. E o caso de teste é:

  • anNum > = 2 -> O aplicativo não falha e você pode ver a sequência de log: "Esta instrução será executada quando anNum <2" na janela do console de log outPut
  • anNum <2 -> O aplicativo falhará e você não poderá ver a sequência de log: "Esta instrução será executada quando anNum <2"

fonte
1
Você entendeu o contrário. "NSAssert faz com que o aplicativo falhe quando corresponde à condição. Se não corresponder à condição, as próximas instruções serão executadas". NSAssert trava o aplicativo se NÃO corresponder à condição e será executado normalmente se corresponder à condição.
18715 Joe
O aplicativo falha e registra a mensagem quando não atende à condição, caso contrário, ele executa mais.
Pravin S.