¿Cuál es una manera confiable de hacer que una aplicación iOS se bloquee?

136

Quiero probar el informe de fallos de mi aplicación en el campo haciendo que se bloquee deliberadamente cuando el usuario realiza una acción particular que es poco probable que un usuario real realice accidentalmente.

Pero, ¿cuál es una buena forma confiable de hacer que la aplicación se bloquee que no cree una advertencia en el momento de la compilación?

Editar: Tenga en cuenta que muchas respuestas aparentemente obvias a esta pregunta dan como resultado excepciones que quedan atrapadas por Cocoa y, por lo tanto, no provocan el bloqueo de la aplicación.

Néstor
fuente
¡Estoy obteniendo WebKit discarded an uncaught exceptiontodas estas ideas hasta ahora! ¿Quién sabía que era tan difícil hacer que una aplicación se bloquee en estos días?
Nestor
No creo que ninguno de estos tenga algo que ver con WebKit ...
BoltClock
23
Sí, abra Safari en un iPad 1 y vaya a una página con muchas imágenes. Siempre funciona para mi. : /
Alan B
44
(void)0/0;,(void)*(char*)0;
Kevin
1
Tenga cuidado con algunas de las respuestas aquí que invocan un comportamiento indefinido . ¡Eso es realmente un consejo muy desagradable!
Usr

Respuestas:

140

en Objective-C use C directamente para causar un mal acceso

strcpy(0, "bla");

Nota: si bien esto funciona en cualquier sistema que conozco, en una versión futura del tiempo de ejecución de C O en el compilador, esto podría no provocar un bloqueo más. ver ¿Es el comportamiento indefinido de desreferencia de puntero nulo en Objective-C? )

(en rápido tendrías que hacer un puente a objC para hacer esto)

Daij-Djan
fuente
esta es la manera más confiable de mi humilde opinión
Michał Kreft
Ah sí, eso WebKit discarded an uncaught exceptiontambién soluciona el problema.
Nestor
todavía había un error tipográfico: D no @ "bla" pero "bla"
Daij-Djan
44
Aparentemente ( stackoverflow.com/questions/13651642/… ), este es un comportamiento indefinido y en realidad es una respuesta muy mala. El compilador puede optimizar legalmente ambas declaraciones y simplemente no hacer nada. Te sugiero que elimines esta respuesta. Podría llevar a las personas a hacer esto realmente.
Usr
3
en ios y osx y windows y redhat siempre se ha bloqueado, así que en el contexto dado, diría que es válido. Agregaré un descargo de responsabilidad
Daij-Djan
97

Mi favorito actual:

assert(! "crashing on purpose to test <insert your reason here>");

Un clásico:

kill( getpid(), SIGABRT );

Y algunas pr0n:

*(long*)0 = 0xB16B00B5;

Todos ellos generan bloqueos capturados por mi herramienta de informe de bloqueo.

djromero
fuente
14
afirmar no se bloquea en las versiones de lanzamiento, por eso es una
afirmación
66
depende de la configuración de compilación; Además, creo que la pregunta es sobre las pruebas, parece correcto mantener las
afirmaciones
3
Mucha gente (incluido yo) deja afirmaciones en las versiones de lanzamiento. No hay razón para deshabilitarlos.
Sulthan
55
@Sulthan: assert()es una función de depuración, no tiene mucho sentido dejar tal ruft en las versiones de lanzamiento. Hay pruebas unitarias para eso.
MestreLion
18
En mi humilde opinión assertno es una función de depuración. Una afirmación fallida es un error que creías imposible. Es mejor abortar, incluso una versión de lanzamiento, que seguir ejecutando un programa con consecuencias impredecibles.
djromero
27

Como todos usamos Clang para iOS, esto es bastante confiable:

__builtin_trap();

Esto tiene el beneficio de que está diseñado exactamente para este propósito, por lo que no debería generar advertencias o errores del compilador.

Dietrich Epp
fuente
22

¿Qué tal un buen desbordamiento de pila viejo :)

- (void)stackOverflow
{
    [self stackOverflow];
}
Taum
fuente
16

El más popular: bloqueo de selector no reconocido:

NSObject *object = [[NSObject alloc] init];
[object performSelector:@selector(asfd)];

Asegúrese de no tener el método -asdf implementado en esa clase jaja

O indice más allá de la excepción encuadernada:

NSArray * array = [NSArray array];
[array objectAtIndex:5];

Y por supuesto kill( getpid(), SIGABRT );

wirrwarr
fuente
12

Creo que en Swift podrías lanzar fácilmente un error fatal:

func foo() {
    fatalError("crash!")
}

En realidad, incluso está destinado a usar esta función en caso de que algo salga mal para que la aplicación se bloquee.

Para evitar una declaración if en un caso especial, también puede usarla precondition. Es similar a assert, deja así clara la intención (si se desea) y no se elimina en la versión final como assert. Se usa como precondition(myBoolean, "This is a helpful error message for debugging.").

borchero
fuente
9

Enviar un mensaje a un objeto desasignado

Andrey Chernukha
fuente
34
Esto en realidad es muy poco confiable. Aún puede enviar mensajes a objetos desasigados siempre que su memoria no se reutilice. Esta es la razón por la cual las personas han tenido históricamente dificultades para depurar errores de doble versión. Es solo cuando la memoria es reclamada por otro objeto que enviar un mensaje puede causar una excepción.
Mike Weller
7
exit(0);

(debe ... escribir ... 30 caracteres)

Steve Rogers
fuente
Gracias por los votos a favor, pero de hecho esto hará que la aplicación finalice y regrese a Springboard, que, aunque puede ser útil en sí misma, no es lo que OP quería, que es desencadenar una excepción no atrapada
Steve Rogers,
6

También puede plantear una excepción:

[NSException raise:NSInternalInconsistencyException
            format:@"I want to test app crashes!."];
Alessandro Vendruscolo
fuente
2
No creo que la excepción sea esa buena manera, la captura de la excepción es común, por lo que podría atraparla accidentalmente. La captura de señales no es tan común, por lo que un mal acceso o cosas similares serían más confiables. :)
Michał Kreft
3

Agregue un reconocedor de gestos a una vista que reconozca un toque de 10 dedos (5 dedos para iPhone, ya que 10 pueden llenarse un poco). El GR tiene un método adjunto que ejecuta cualquiera de las formas seguras antes mencionadas de hacer que su aplicación se bloquee. La mayoría de los usuarios no van a poner 10 dedos sobre tu aplicación, por lo que estás a salvo del usuario general que accidentalmente causa el bloqueo.

Sin embargo, debería poder usar algo como Testflight o simplemente implementarlo en dispositivos personales y realizar pruebas en la naturaleza antes de enviarlo a Apple. Tener un bloqueo forzado podría hacer que Apple rechace tu aplicación.

jhelzer
fuente
Mi aplicación Cocos2d se bloquea cuando hago un toque múltiple extremo, y lo tengo como un error no resuelto. No tengo ningún GR, pero he habilitado multitouch en Cocos2d. ¿Experimento el accidente que usted describe? ¿Quiere decir que esto es comportamiento esperado / deseado?
Fredrik Johansson
@Fredrik No creo que se espere el bloqueo que está describiendo (nunca se deben esperar bloqueos de la OMI y personalmente no creo que sea una buena idea poner uno a propósito en su aplicación). Podría intentar simbolizar el bloqueo y averiguar exactamente qué método está causando el bloqueo de la aplicación. Podría ser algo dentro del marco de Cocos2d que está causando el bloqueo cuando ocurre el 'toque múltiple extremo'. Si ese es el caso, entonces su mejor opción es presentar un error con los chicos de Cocos2d.
jhelzer
2

podría intentar algo como

NSArray* crashingArray = [NSArray arrayWithCapacity:1];
[crashingArray release];

debería bloquearse en un EXC_BAD_ACCESS (podría necesitar liberarlo por segunda vez, pero normalmente ya debería bloquearse así)

Saliom
fuente
3
No compilará con ARC habilitado.
vikingosegundo
bueno, si usas ARC también puedes hacer esto: NSArray * crashingArray = [NSArray arrayWithCapacity: 1]; [crashingArray objectAtIndex: 0]; esto debería estar fallando
Saliom 01 de
1

Yo iré con:int raise(int sig);

Para obtener más información. >man raise

Vitautas
fuente
0

Simplemente mataría el proceso normalmente:

kill(getpid(), SIGKILL);

Entonces, si instala un controlador con señal, también puede manejar el bloqueo, terminando de escribir los archivos abiertos y estas cosas.

Ramy Al Zuhouri
fuente
esto ya está incluido en la respuesta de madmw
vikingosegundo
0

yo suelo

[self doesNotRecognizeSelector:_cmd]; 
Duyen-Hoa
fuente
2
Esta publicación se marca automáticamente como de baja calidad porque solo es código. ¿Le importaría expandirlo agregando texto para explicar por qué esto resuelve el problema?
gung - Restablecer Monica
0

Cuando trabajo con RubyMotion, uso esto:

    n=Pointer.new ('c', 1)
    n[1000] ='h'
Raymond
fuente
0

Prueba esto:

- (IBAction)Button:(id)sender
{
    NSArray *array = [NSArray new];
    NSLog(@"%@",[array objectAtIndex:8]);
}
Rajesh Loganathan
fuente
-1

una NSLogdeclaración incorrecta lo hará

NSLog(@"%@",1);
Mutawe
fuente