Qual è il punto di NSAssert, in realtà?


155

Devo chiederlo, perché: l'unica cosa che riconosco è che se l'asserzione fallisce, l'app si blocca. È questo il motivo per cui utilizzare NSAssert? O cos'altro ne trae vantaggio? Ed è giusto mettere un NSAssert appena al di sopra di qualsiasi ipotesi che faccio nel codice, come una funzione che non dovrebbe mai ricevere un -1 come parametro ma che può essere -0.9 o -1.1?

Risposte:


300

Asserire è assicurarsi che un valore sia quello che dovrebbe essere. Se un'asserzione fallisce significa che qualcosa è andato storto e quindi l'app si chiude. Un motivo per usare assert sarebbe se hai qualche funzione che non si comporterà o creerà effetti collaterali molto cattivi se uno dei parametri passati ad esso non è esattamente un valore (o un intervallo di valori) che puoi mettere un'asserzione da fare certo che quel valore è quello che ti aspetti che sia, e se non lo è allora qualcosa è davvero sbagliato, e così l'app si chiude. Assert può essere molto utile per il debug / unit test e anche quando si forniscono framework per impedire agli utenti di fare cose "cattive".


9
Dovresti eliminare NSAssert per il rilascio. C'è un flag di compilazione per farlo.
Barry Wark,

127
> È necessario eliminare NSAssert per il rilascio. Questo è discutibile. Rilascio sempre le mie applicazioni con le asserzioni abilitate, e questa è una pratica standard per molti software, ad esempio Apple lo fa. Non appena il programma ha rilevato uno stato anomalo, è necessario arrestarsi in modo anomalo. È possibile ottenere una traccia dello stack di dove si è verificato l'errore, mentre se si disabilitano le affermazioni si potrebbe finire per corrompere la memoria e / oi dati dell'utente e il problema sarà molto difficile da debug.
Mike Weller,

18
Si noti che XCode 4 ha NS_BLOCK_ASSERTIONS definito per impostazione predefinita nelle configurazioni di rilascio. Immagino che se non cambi che il tuo codice rilasciato non conterrà NSAssert: s.
Jonny il

16
Se ho capito bene, che senso ha lasciarli (nella versione di rilascio)? Perché non sostituire NSAssert con un'istruzione if e if (succede qualcosa di terribile), quindi informare l'utente (o fare qualcosa che è sotto il tuo controllo) e non solo uscire / arrestarsi e lasciare che l'utente si chieda cosa è successo ... O mi sto perdendo qualcosa?
Gik,

11
È una perdita di tempo per gli sviluppatori percorrere la strada di ogni caso eccezionale che non dovrebbe accadere affatto in circostanze normali. Ciò implica pensare a modi appropriati per informare l'utente per ciascuno di essi e / o rendere l'app abbastanza robusta da continuare in modo previsto dopo il loro verificarsi. L'approccio più pratico è quello di arrestare l'app in modo anomalo e correggere il bug trovato nel rapporto di arresto anomalo e rilasciare una nuova versione. Detto questo, è importante assicurarsi che non vi siano perdite di dati in tali situazioni. Ciò deve essere garantito comunque, ma è un lavoro molto minore.
trss,

20

Non posso davvero parlare con NSAssert, ma immagino che funzioni in modo simile a C's assert ().

assert () viene utilizzato per applicare un contratto semantico nel codice. Cosa significa che chiedi?

Bene, è come hai detto: se hai una funzione che non dovrebbe mai ricevere un -1, puoi avere assert () imporre che:

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

E ora vedrai qualcosa di simile nel registro degli errori (o STDERR):

Asserzione i> 0 non riuscita: file esempio.c, riga 2

Quindi non solo protegge dagli input potenzialmente dannosi, ma li registra in modo utile e standard.

Oh, e almeno in C assert () era una macro, quindi puoi ridefinire assert () come no-op nel tuo codice di rilascio. Non so se questo sia il caso di NSAssert (o anche più di assert ()), ma è stato abbastanza utile compilare quei controlli.


2
Sì, NSAssert è anche una macro.
Martin Wickman,

18

NSAssertti dà molto più del semplice arresto anomalo dell'app. Indica la classe, il metodo e la riga in cui si è verificata l'asserzione. Tutte le asserzioni possono anche essere facilmente disattivate usando NS_BLOCK_ASSERTIONS. Rendendolo quindi più adatto per il debug. D'altra parte, lanciare un NSExceptionsolo si blocca l'app. Inoltre non indica la posizione dell'eccezione, né può essere disabilitato in modo così semplice. Vedi la differenza nelle immagini qui sotto.

L'app si arresta in modo anomalo perché un'asserzione solleva anche un'eccezione, come afferma la documentazione di NSAssert :

Quando viene richiamato, un gestore asserzioni stampa un messaggio di errore che include i nomi dei metodi e delle classi (o il nome della funzione). Quindi genera un'eccezione NSInternalInconsistencyException.

NSAssert:

Registra dopo un'asserzione

NSException:

Registra dopo un'eccezione


An NSExceptionoffre molte opportunità di personalizzare l'output che restituisce tramite i parametri reasone userInfo. Non c'è motivo per cui non sia possibile aggiungere il nome della classe, il selettore, le informazioni sulla linea e qualsiasi altra cosa che si desidera aggiungere per facilitare il debug. IMHO, lo usi NSAssertper scopi di debug durante lo sviluppo ma li disabiliti per la spedizione; si lancia un NSExceptionse si desidera lasciare un'asserzione nel codice di spedizione.
markeissler,

17

A parte ciò che tutti hanno detto sopra, il comportamento predefinito NSAssert()(a differenza di quelli di C assert()) è quello di lanciare un'eccezione, che puoi catturare e gestire. Ad esempio, Xcode fa questo.


C'è di più su come possiamo catturare e gestire l'eccezione?
Andato il

1
Le eccezioni nel cacao NON sono di fatto "catturabili e manipolabili". Se il controllo passa attraverso una funzione Apple in qualsiasi punto dell'albero delle chiamate, il comportamento non è definito. Le eccezioni sono puramente per la segnalazione di errori (aka, crittercism, ecc.), Non per uso generale come in Java.
Michael

9

Solo per chiarire, come qualcuno ha menzionato ma non completamente spiegato, il motivo per avere e usare assert invece di creare semplicemente codice personalizzato (fare if e sollevare un'eccezione per dati errati, per esempio) è che gli assalti DOVREBBERO essere disabilitati per le applicazioni di produzione.

Durante lo sviluppo e il debug, gli assert ti consentono di rilevare errori. Il programma si interromperà quando un'asserzione viene valutata come falsa. Ma, durante la compilazione per la produzione, il compilatore omette il codice di asserzione e REALIZZA IL PROGRAMMA RUN FASTER. A quel punto, si spera, hai risolto tutti i bug. Nel caso in cui il programma presenti ancora dei bug durante la produzione (quando le asserzioni sono disabilitate e il programma "salta" le asserzioni), il programma finirà probabilmente per bloccarsi in qualche altro punto.

Dall'aiuto di NSAssert: "Le asserzioni sono disabilitate se viene definita la macro del preprocessore NS_BLOCK_ASSERTIONS." Quindi, basta inserire la macro nella destinazione di distribuzione [solo].


6

NSAssert(e il suo equivalente stdlib assert) devono rilevare errori di programmazione durante lo sviluppo. Non si dovrebbe mai avere un'asserzione che fallisce in un'applicazione di produzione (rilasciata). Quindi potresti affermare che non passi mai un numero negativo a un metodo che richiede un argomento positivo. Se l'affermazione non riesce mai durante il test, hai un bug. Se, tuttavia, il valore che viene passato viene inserito dall'utente, è necessario eseguire una corretta convalida dell'input anziché fare affidamento sull'asserzione in produzione (è possibile impostare un #define per build di rilascio che disabilita NSAssert*.


2
+1 perché la tua risposta ha più senso per me! L'uso di NSAssert ha più senso se è destinato allo sviluppo, non dopo il rilascio. Un utente che immette un valore non consentito deve essere seguito da un errore dell'interfaccia utente, non da NSAssert che provoca l'arresto anomalo dell'applicazione. La nebbia si è schiarita!
pnizzle

3

Le asserzioni sono comunemente usate per imporre l'uso previsto di un particolare metodo o pezzo di logica. Diciamo che stavi scrivendo un metodo che calcola la somma di due numeri interi maggiori di zero. Al fine di accertarti che il metodo sia sempre stato usato come previsto, probabilmente faresti un'affermazione che verifica tale condizione.

Risposta breve: impongono che il codice venga utilizzato solo come previsto.



2

Per rispondere pienamente alla sua domanda, il punto di qualsiasi tipo di asserzione è di facilitare il debug. È più utile rilevare gli errori alla fonte, quindi rilevarli nel debugger quando provocano arresti anomali.

Ad esempio, è possibile passare un valore a una funzione che prevede valori in un determinato intervallo. La funzione può archiviare il valore per un uso successivo e in seguito l'uso degli arresti anomali dell'applicazione. Lo stack di chiamate visualizzato in questo scenario non mostra l'origine del valore errato. È meglio catturare il valore negativo quando arriva per scoprire chi sta passando il valore negativo e perché.


-3

NSAssertrendere l'app in crash quando corrisponde alla condizione. Se non corrispondono alla condizione, verranno eseguite le istruzioni successive. Cerca l'EX di seguito:

Ho appena creato un'app per testare qual è il compito di 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");
}

nel mio codice l'app non si arresterà in modo anomalo e il test case è:

  • anNum > = 2 -> L'app non si arresta in modo anomalo e puoi vedere la stringa di registro: "Questa istruzione verrà eseguita quando anNum <2" nella finestra della console di registro di outPut
  • anNum <2 -> L'app si arresterà in modo anomalo e non è possibile visualizzare la stringa di registro: "Questa istruzione verrà eseguita quando anNum <2"

1
Hai fatto il contrario. "NSAssert provoca l'arresto anomalo dell'app quando corrisponde alla condizione. In caso contrario, verranno eseguite le istruzioni successive". NSAssert arresta in modo anomalo l'app se NON corrisponde alla condizione ed esegue normalmente se NON corrisponde alla condizione.
Joe Tam,

L'app si arresta in modo anomalo e registra il messaggio quando non soddisfa la condizione, altrimenti viene eseguita ulteriormente.
Pravin S.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.