O que é uma maneira confiável de travar um aplicativo iOS?

136

Desejo testar os relatórios de falhas do meu aplicativo em campo deliberadamente, quando o usuário executa uma ação específica que é improvável que um usuário real execute acidentalmente.

Mas qual é uma boa maneira confiável de travar o aplicativo que não cria um aviso no momento da compilação?

Edit: Observe que muitas respostas aparentemente óbvias para essa pergunta resultam em exceções que são capturadas pelo cacau e, portanto, não resultam no travamento do aplicativo.

Nestor
fonte
Estou recebendo WebKit discarded an uncaught exceptiontodas essas idéias até agora! Quem sabia que era tão difícil fazer um aplicativo travar hoje em dia?
Nestor
Eu não acho que nada disso tenha algo a ver com o WebKit ...
BoltClock
23
Sim, abra o Safari no iPad 1 e navegue até uma página com muitas imagens. Sempre funciona para mim. : /
Alan B
4
(void)0/0;,(void)*(char*)0;
Kevin
1
Tenha cuidado com algumas das respostas aqui, invocando um comportamento indefinido . Na verdade, esse é um conselho muito desagradável!
usr

Respostas:

140

no Objective-C, use C diretamente para causar um mau acesso

strcpy(0, "bla");

Nota: enquanto isso funciona em qualquer sistema que eu conheço - em uma versão futura do tempo de execução C OU no compilador, isso pode não levar mais a uma falha. consulte O comportamento nulo da dereferência de ponteiro nulo é definido em Objective-C? )

(rapidamente, você teria que fazer uma ponte para objC para fazer isso)

Daij-Djan
fonte
este é IMHO a maneira mais confiável
Michał Kreft
Ah, sim, isso também contorna o WebKit discarded an uncaught exceptionproblema.
Nestor
houve um erro de digitação ainda: no D @ "bla", mas "bla"
Daij-Djan
4
Aparentemente ( stackoverflow.com/questions/13651642/… ), esse é um comportamento indefinido e, na verdade, uma resposta muito ruim! O compilador pode otimizar legalmente as duas instruções e simplesmente não fazer nada. Eu sugiro que você exclua esta resposta. Isso pode levar as pessoas a realmente fazer isso.
usr
3
em ios e osx e windows e redhat sempre falhava assim no contexto dado, eu diria que é válido. Vou adicionar um aviso de isenção de responsabilidade
Daij-Djan
97

Meu favorito atual:

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

Um clássico:

kill( getpid(), SIGABRT );

E alguns pr0n:

*(long*)0 = 0xB16B00B5;

Todos eles geram falhas capturadas pela minha ferramenta de relatório de falhas.

djromero
fonte
14
assert não falha nas versões de lançamento, é por isso que é uma afirmação #
DarthMike
6
isso depende das suas configurações de compilação; Além disso, eu acho que a pergunta é sobre o teste, parece ok para manter afirma no teste constrói
djromero
3
Muitas pessoas (inclusive eu) deixam declarações nas versões de lançamento. Não há motivo para desativá-los.
Sulthan
5
@ Sulthan: assert()é um recurso de depuração, faz pouco sentido deixar esse fragmento nas versões de lançamento. Existem testes de unidade para isso.
MestreLion
18
IMHO assertnão é um recurso de depuração. Uma afirmação falhada é um erro que você julgou impossível. É melhor abortar, mesmo uma versão, do que continuar executando um programa com consequências imprevisíveis.
djromero
27

Como todos usamos o Clang para iOS, isso é bastante confiável:

__builtin_trap();

Isso tem o benefício de ter sido projetado exatamente para esse fim, portanto não deve gerar avisos ou erros do compilador.

Dietrich Epp
fonte
22

Que tal um bom e velho estouro de pilha :)

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

Um dos mais populares - falha seletora não reconhecida:

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

Verifique se você não possui o método -asdf implementado nessa classe haha

Ou indexe além da exceção vinculada:

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

E claro kill( getpid(), SIGABRT );

wirrwarr
fonte
12

Eu acho que no Swift você pode facilmente lançar um erro fatal:

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

Na verdade, pretende-se usar esse recurso, caso algo dê errado, a fim de causar o travamento do aplicativo.

Para evitar uma declaração if em um caso especial, você também pode usar precondition. É semelhante a assert, torna assim a intenção (se desejada) bastante clara e não é removida no lançamento final como assert. É usado como precondition(myBoolean, "This is a helpful error message for debugging.").

borchero
fonte
9

Enviar uma mensagem para um objeto desalocado

Andrey Chernukha
fonte
34
Isso é realmente muito pouco confiável. Você ainda pode enviar mensagens para objetos desalocados, desde que a memória não seja reutilizada. Essa é toda a razão pela qual as pessoas historicamente tiveram muita dificuldade em depurar erros de liberação dupla. É somente quando a memória é recuperada por outro objeto que o envio de uma mensagem pode causar uma exceção.
Mike Weller
7
exit(0);

(deve ... digitar ... 30 caracteres)

Steve Rogers
fonte
Obrigado pelas upvotes mas na verdade isso fará com que o aplicativo terminar e retornar ao Springboard, que, embora possa ser útil em si mesmo, não é o OP queria, que é para acionar uma exceção untrapped
Steve Rogers
6

Você também pode gerar uma exceção:

[NSException raise:NSInternalInconsistencyException
            format:@"I want to test app crashes!."];
Alessandro Vendruscolo
fonte
2
Eu não acho que a exceção seja assim, é comum capturar uma exceção para que você possa capturá-la acidentalmente. Capturar sinais não é tão comum, portanto, um acesso ruim ou coisas semelhantes seriam mais confiáveis. :)
Michał Kreft
3

Adicione um reconhecedor de gestos a uma exibição que reconheça um toque de 10 dedos (5 dedos para iPhone, pois 10 podem ficar um pouco cheios). O GR possui um método anexado que executa qualquer uma das maneiras infalíveis mencionadas anteriormente para travar o aplicativo. A maioria dos usuários não coloca dez dedos no seu aplicativo, portanto, você estará protegido contra o usuário geral que causa o acidente acidentalmente.

No entanto, você deve poder usar algo como o Testflight ou simplesmente implantá-lo em dispositivos pessoais e testar em ambiente selvagem antes de enviá-lo à Apple. Ter uma falha forçada pode fazer com que seu aplicativo seja rejeitado pela Apple.

jhelzer
fonte
Meu aplicativo Cocos2d trava quando eu faço um multitoque extremo, e eu tenho isso como um bug não resolvido. Não tenho nenhum GR, mas habilitei o multitoque no Cocos2d. Eu experimento a falha que você descreve? Você quer dizer que esse comportamento é esperado / desejado?
Fredrik Johansson
@ Fredrik: Eu não acho que você está travando, o que está descrevendo é esperado (as falhas da IMO nunca devem ser esperadas e, pessoalmente, não acho que seja uma boa ideia colocar propositalmente uma no seu aplicativo). Você pode tentar simbolizar a falha e descobrir exatamente qual método está causando a falha do aplicativo. Pode ser algo dentro da estrutura do Cocos2d que está causando o travamento quando ocorre o 'extremo multitoque'. Se for esse o caso, sua melhor aposta é arquivar um bug com o pessoal do Cocos2d.
Jhelzer #
2

poderia tentar algo como

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

deve travar em um EXC_BAD_ACCESS (pode ser necessário liberá-lo uma segunda vez, mas normalmente já deve travar assim)

Saliom
fonte
3
Não será compilado com o ARC ativado.
22712 vikingosegundo
bem, se você pode usar o ARC, você também pode fazer isso: NSArray * crashingArray = [NSArray arrayWithCapacity: 1]; [crashingArray objectAtIndex: 0]; isso deve estar deixando de funcionar
#
1

Eu irei com:int raise(int sig);

Para obter mais informações >man raise

Vytautas
fonte
0

Eu mataria o processo normalmente:

kill(getpid(), SIGKILL);

Portanto, se você instalar um manipulador com sinal, também poderá lidar com a falha, terminando de gravar arquivos abertos e essas coisas.

Ramy Al Zuhouri
fonte
isso já está incluído na resposta da madmw
vikingosegundo
0

eu uso

[self doesNotRecognizeSelector:_cmd]; 
Duyen-Hoa
fonte
2
Esta postagem está sendo sinalizada automaticamente como baixa qualidade porque é apenas um código. Você se importaria de expandi-lo adicionando algum texto para explicar por que isso resolve o problema?
gung - Reintegrar Monica
0

Ao trabalhar com RubyMotion, eu uso este:

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

Tente o seguinte:

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

uma NSLogdeclaração errada fará isso

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