Atualização 30/01/19
Embora essa resposta possa funcionar, a solução recomendada para uma verificação estática (conforme esclarecido por vários engenheiros da Apple) é definir um sinalizador de compilador personalizado direcionado aos simuladores do iOS. Para instruções detalhadas sobre como fazer isso, consulte a resposta de @ mbelsky .
Resposta original
Se você precisar de uma verificação estática (por exemplo, não um tempo de execução, se / else), não poderá detectar o simulador diretamente, mas poderá detectar o iOS em uma arquitetura de desktop, como segue
#if (arch(i386) || arch(x86_64)) && os(iOS)
...
#endif
Após a versão Swift 4.1
Uso mais recente, agora diretamente para todos em uma condição, para todos os tipos de simuladores precisam aplicar apenas uma condição -
#if targetEnvironment(simulator)
// your simulator code
#else
// your real device code
#endif
Para mais esclarecimentos, você pode verificar a proposta Swift SE-0190
Para versão mais antiga -
Claramente, isso é falso em um dispositivo, mas retorna verdadeiro para o iOS Simulator, conforme especificado na documentação :
A configuração de construção do arch (i386) retorna verdadeira quando o código é compilado para o simulador iOS de 32 bits.
Se você estiver desenvolvendo para um simulador que não seja o iOS, basta alterar o os
parâmetro: por exemplo
Detectar o simulador watchOS
#if (arch(i386) || arch(x86_64)) && os(watchOS)
...
#endif
Detectar o simulador de tvOS
#if (arch(i386) || arch(x86_64)) && os(tvOS)
...
#endif
Ou, até, detectar qualquer simulador
#if (arch(i386) || arch(x86_64)) && (os(iOS) || os(watchOS) || os(tvOS))
...
#endif
Se você estiver bem com uma verificação de tempo de execução, poderá inspecionar a TARGET_OS_SIMULATOR
variável (ou TARGET_IPHONE_SIMULATOR
no iOS 8 e abaixo), que é verdadeira em um simulador.
Observe que isso é diferente e um pouco mais limitado do que usar um sinalizador de pré-processador. Por exemplo, você não poderá usá-lo no lugar onde a if/else
é sintaticamente inválido (por exemplo, fora do escopo das funções).
Digamos, por exemplo, que você deseja ter importações diferentes no dispositivo e no simulador. Isso é impossível com uma verificação dinâmica, enquanto que é trivial com uma verificação estática.
#if (arch(i386) || arch(x86_64)) && os(iOS)
import Foo
#else
import Bar
#endif
Além disso, como o sinalizador é substituído por a 0
ou a 1
pelo pré-processador rápido, se você o usar diretamente em uma if/else
expressão, o compilador emitirá um aviso sobre código inacessível.
Para contornar esse aviso, consulte uma das outras respostas.