Controle de Fluxo

O Swift fornece uma variedade de comandos para controle de fluxo. Estes incluem loops while para executar uma tarefa várias vezes, os comandos if, guard e switch para executar diferentes trechos de código com base em certas condições; e comandos como break e continue para transferir o fluxo de execução para outro ponto em seu código.

Ele também fornece o comando de loop for-in que facilita a iteração em arrays, dictionaries, ranges, strings e outras seqüências.

A declaração do comando switch do Swift é consideravelmente mais poderosa do que em muitas linguagens parecidas com C. Os blocos case podem combinar muitos padrões diferentes, incluindo combinações de valores, tuplas e fazer casts para um tipo específico. Os valores correspondentes em um bloco case de um switch podem ser vinculados a constantes ou variáveis temporárias ​para serem usados dentro do bloco case, e condições complexas podem ser expressas com uma cláusula where para cada bloco case.

Loops For-In

Você pode usar o comando de loop for-in para iterar sobre uma sequencia como items de um array, ranges de números ou os caracteres de uma string.

Este exemplo usa um comando de loop for-in para iterar sobre os items de um array:

Você também pode iterar sobre um dictionary para acessar seus pares de chave-valor. Cada item no dictionary é retornado como uma tupla (chave, valor) quando o dicionário é iterado e você pode decompor os membros da tupla (chave, valor) como constantes com nomes específicos para uso dentro do bloco do loop for-in. No exemplo de código abaixo, as chaves do dictionary são decompostas em uma constante chamada animalName, e os valores do dictionary são decompostos em uma constante chamada legCount.

Os conteúdos de um Dictionary são desordenados e a iteração sobre eles não garante a ordem em que serão recuperados. Em particular, a ordem em que você insere itens em um Dictionary não define a ordem em que são iterados. Para mais informações sobre arrays e dictionaries, consulte a seção Tipos de Coleção.

Você também pode usar comandos de loops for-in com ranges numéricos. Este exemplo imprime os primeiras resultados de uma tabela de multiplicação do número cinco :

A sequência que está sendo iterada é uma range de números de 1 a 5 do tipo inclusiva conforme indicado pelo uso do operador de range fechado .... O valor de index é definido como o primeiro número no intervalo 1, e as instruções dentro do loop são executadas. Nesse caso, o loop contém apenas uma instrução, que imprime o resultado da tabela de multiplicação do número cinco vezes o valor atual do índice. Depois que a instrução é executada, o valor de index é atualizado para conter o segundo valor no intervalo 2 e a função print(_: separador: terminador :) é chamada novamente. Este processo continua até o final do intervalo alcançado.

No exemplo acima, o índice é uma constante cujo valor é definido automaticamente no início de cada iteração do loop. Assim, o índice não precisa ser declarado antes de ser usado, pois é implicitamente declarado simplesmente ao incluí-lo na declaração do loop, sem a necessidade de usar o comando let.

Se você não precisa de cada valor que está sendo iterado, ignore os valores usando um underscore no lugar de um nome de variável.

O exemplo acima calcula o valor de um número para o potência (power em inglês) de outro, neste caso, 3 na potência de 10. Ele multiplica um valor inicial de 1 (isto é, 3 para a potência de 0) com 3, dez vezes, usando um range fechado que começa com 1 e termina com 10. Para esse cálculo, o contador individual cada vez que o loop é desnecessário, portanto o código simplesmente executa o loop o número correto de vezes. O caractere de underscore _ usado no lugar de uma variável no loop faz com que os valores individuais sejam ignorados e não forneçam acesso ao valor atual durante cada iteração do loop.

Em algumas situações, talvez você não queira usar ranges fechados, que incluem o início e o fim do range. Imagine desenhar as marcas para cada minuto em relógio. Você quer desenhar 60 marcas, começando no 0 minutos. Use o operador de range semi-aberto ..< para dizer que o limite precisa ser inferior ao número da direita, e não superior ou igual. Para obter mais informações sobre os ranges, consulte a seção de Operadores de Range.

Alguns usuários podem querer menos marcações na sua IU. Podem preferir uma marca a cada 5 minutos. Use a função stride(from: to: by :) para ignorar as marcas indesejadas.

Ranges fechados também estão disponíveis usando a funcão stride(from: through: by:) :

Loops While

Um loop while executa um conjunto de instruções até uma condição se tornar falsa. Esses tipos de loops são usados ​​com mais frequência quando o número de iterações não é conhecido antes da primeira iteração começar. O Swift fornece dois tipos de loops do tipo while:

  • O while avalia a condição no início de cada passagem pelo loop.
  • O repeat-while avalia a condição no final de cada passagem pelo loop.

While

O loop while começa por avaliar uma única condição, se a condição for verdadeira, um conjunto de instruções será repetido até a condição se tornar falsa. Aqui está um exemplo geral de um loop while:

O exemplo abaixo joga um simples jogo de Snakes and Ladders (também conhecidas como Chutes and Ladders):

As regras para o jogo são as seguintes:

  • O Tabuleiro tem 25 quadrados, e o objetivo é pousar no quadrado 25 ou além.
  • O quadrado de partida do jogador é o "quadrado zero", que está abaixo do canto inferior esquerdo do tabuleiro.
  • Cada turno, você rola um dado de seis lados e se move pelo número de quadrados correspondente ao número do dado, seguindo o caminho horizontal indicado pela flecha pontilhada acima.
  • Se o seu turno terminar e você estiver abaixo de uma escada, você se move acima dessa escada.
  • Se o seu turno terminar e você estiver na cabeça de uma cobra, você se move para baixo dessa cobra.

O tabuleiro do jogo é representado por um array de valores do tipo Int. Seu tamanho é baseado em uma constante chamada finalSquare, que é usada para inicializar o array e também para verificar uma condição de vitória mais adiante no exemplo. Como os jogadores começam fora do tabuleiro, no "quadrado zero", a placa é inicializada com 26 valores zero do tipo Int, não 25.

Alguns quadrados são definidos para ter valores mais específicos para as cobras e escadas. Os quadrados com uma base de escada têm um número positivo para movê-lo no quadro, enquanto os quadrados com uma cabeça de cobra têm um número negativo para movê-lo de volta ao tabuleiro.

O quadrado 3 contém a base de uma escada que o move o jogador até o quadrado 11. Para representar isso, o array board[03] é igual a +08, o que equivale a um valor inteiro de 8 (a diferença entre 3 e 11). Para alinhar os valores e as declarações, o operador unário mais +i é explicitamente usado com o operador unário menos -i e os números inferiores a 10 são preenchidos com zeros. (Essa técnica estética não é estritamente necessária, mas elas levam ao código mais claro e fácil de entender).

O exemplo acima usa uma abordagem muito simples para a rolagem de dados. Em vez de gerar um número aleatório, ele começa com o valor de diceRoll igual a 0. Cada vez que o comando while realiza um loop, diceRoll é incrementado em 1 e, em seguida, é verificado para ver se ele se tornou maior que os números diponíveis no dado. Sempre que valor retornado é igual a 7, a rolagem dos dados tornou-se muito grande e é reiniciado para o valor 1. O resultado é uma seqüência de valores para diceRoll que é sempre 1, 2, 3, 4, 5, 6, 1, 2 e assim por diante.

Depois de rodar os dados, o jogador avança pelo número de quadrados equivalente ao valor de diceRoll. É possível que a rolagem de dados tenha movido o jogador além do quadrado 25, caso em que o jogo acaba. Para lidar com esse cenário, o código verifica se square é menor do que a propriedade count do array board. Se square for válido, o valor armazenado no board[square] é adicionado ao valor atual de square para mover o jogador para cima ou para baixo em qualquer escada ou cobra.

Nota

Se essa checagem não fosse executada, o comando board[square] poderia tentar acessar um valor fora dos limites do array board, o que dispararia um erro em tempo de execução.

A execução atual do loop while então termina e a condição é checada novamente para ver se o loop deve ser executado novamente. Se o jogador se moveu no quadrado 25 ou além dele, a condição do loop é avaliada como false e o jogo termina.

Um loop while é apropriado neste caso, porque o comprimento do jogo não é claro no início do loop. Em vez disso, o loop é executado até que uma condição específica seja satisfeita.

Repeat-While

A outra variação do loop while, conhecida como repeat-while, executa uma única vez o bloco do loop primeiro antes de considerar a condição do loop. Então ele continua a repetir até que a condição seja avaliada como false.

Nota

O comando repeat-while do Swift é analogo ao comando do-while em outras linguagens.

Aqui está a forma comum de um loop repeat-while:

Aqui está o exemplo do jogo Snakes and Ladders novamente, escrito como um loop repeat-while ao invés de um loop while. Os valores de finalSquare, board, square e diceRoll são inicializados exatamente da mesma forma do que com um loop while.

Nessa versão do jogo, a primeira ação no loop é verificar se há alguma escada ou uma cobra. Nenhuma escada no tabuleiro leva o jogador diretamente ao quadrado 25 e, portanto, não é possível ganhar o jogo subindo uma escada. Portanto, é melhor verificar se existe uma cobra ou uma escada na primeira ação do loop.

No início do jogo, o jogador está no "quadrado zero". O board[0] é sempre igual a 0 e não tem nnhum efeito se o jogador ficar parado nele.

Depois que o código verifica se há cobras e escadas, o dado é rolado e o jogador é movido para a frente o número de quadrados equivalente ao resultado de diceRoll. A execução atual do loop termina então.

A condição do loop while square < finalSquare é o mesmo que antes, mas desta vez ela não é avaliada até o final da primeira execução do loop. A estrutura do comando repeat-while se encaixa melhor para este jogo do que o loop while no exemplo anterior. No loop repeat-while acima, square += board[square] é sempre executado imediatamente após a condição do loop confirmar que square ainda está no tabuleiro. Esse comportamento remove a necessidade da verificação de limites do array observada na versão do loop while do jogo descrito anteriormente.

Declarações Condicionais

Muitas vezes, é útil executar diferentes partes de código com base em certas condições. Você pode querer executar um código extra quando ocorrer um erro ou exibir uma mensagem quando um valor se torna muito alto ou muito baixo. Para fazer isso, você escreve partes de seu código como condicionais.

O Swift fornece duas maneiras de adicionar blocos condicionais ao seu código: o comando if e o comando switch. Normalmente, você usa o comando if para avaliar condições simples com apenas alguns possíveis resultados. O comando switch é mais adequadi para condições mais complexas com várias combinações possíveis e é útil em situações em que os padrões pode ajudar a selecionar um bloco de código apropriado para ser executado.

Comando if

Na sua forma mais simples, o comando if tem uma unica condição. Ele executa um conjunto de comando somente se essa condição for avaliada como true.

O exemplo acima verifica se a temperatura é inferior ou igual a 32 graus Fahrenheit (o ponto de congelamento da água). Se for, uma mensagem é impressa. Caso contrário, nenhuma mensagem é impressa, e a execução do código continua após o fechamento do bloco if.

O comando if pode fornecer um conjunto alternativo de comandos, conhecido como cláusula else, para situações em que a condição do if é avaliada como false. Esses blocos são indicadas pelo comando else.

Um desses dois blocos de código sempre serão executados. Como a temperatura aumentou para 40 graus Fahrenheit, não é mais frio o suficiente para aconselhar o uso de um cachecol e, portanto, o bloco else é executado.

Você pode adicionar diversos blocos if depois de um comando else para fornecer comparações adicionais:

Aqui, um bloco if foi adicionado para tratar temperaturas particularmente quentes (acima de 86). O bloco com a cláusula else permanece e imprime uma mensagem para qualquer temperatura que não seja tão quente ou tão fria.

A cláusula else final é opcional, no entanto, ela pode ser excluída se o conjunto de condições não precisa ser completo.

Como a temperatura não é nem tão quente e nem tão fria para executar os blocos if ou else if, nenhuma mensagem é mostrada.

Comando switch

O comando switch considera um valor e o compara com vários padrões de correspondência possíveis. Em seguida, ele executa um bloco apropriado de código com base no primeiro padrão que combina e corresponde ao valor. Uma comando switch fornece uma alternativa para o comando if para responder a múltiplos estados que podem acontecer.

Na sua forma mais simples, o comando switch compara um valor com um ou mais valores do mesmo tipo.

Cada comando switch consiste em múltiplos blocos cases possíveis, cada um dos quais começa com o comando case. Além de comparar valores específicos, o Swift fornece várias maneiras para cada bloco case especificar padrões de correspondência mais complexos. Estas opções são descritas mais adiante neste capítulo.

Como o corpo de um comando if, cada case é um bloco separado de execução de código. A declaração do switch determina qual bloco deve ser selecionado. Este procedimento é conhecido como switching, ou seja, selecionar o bloco de código certo para o valor que está sendo considerado.

Todo comando switch deve ser exaustivo. Ou seja, todos os valores possíveis do tipo que está sendo avaliado devem ser acompanhados por um dos cases do switch. Se não for apropriado fornecer um bloco case para cada valor possível, você pode definir um case padrão para cobrir quaisquer valores que não sejam abordados explicitamente. Este case padrão é indicado pelo comando default e deve sempre aparecer em último lugar.

Este exemplo utiliza um comando switch para considerar um único caractere lowercase chamado someCharacter:

O primeiro case do comando switch corresponde à primeira letra do alfabeto inglês a, e seu segundo case corresponde à última letra z. Como o switch deve ter um case para cada caractere possível, e não apenas para todos os caracteres alfabéticos, esse comando switch usa um case default para validar todos os caracteres que não sejam a e z. Esta abordagem assegura que a declaração do switch seja exaustiva.

Sem fallthrough implícito

Diferentemente do comando switch nas linguagens C e Objective-C, o switch no Swift não fornece o comportamento de fallthrough, isto quer dizer que quando o switch encontra um case para o valor que está sendo comparado, a execução não cai para o próximo bloco case por padrão, ao invés disso, todo o bloco switch termina sua execução assim que o primeiro bloco case é encontrado para o valor que está sendo comparado sem a necessidade do comando break ser usado explicitamente. Isso torna o comando switch mais seguro e fácil de usar se comparado com outras linguagens, além de evitar que outros blocos case sejam executados por engano.

Nota

Mesmo que o comando break não seja obrigatório no Swift, você pode usar um comando break para simplesmente criar e ignorar um bloco case em particular ou para sair de um bloco case antes que ele termine sua execução por completo. Para mais detalhes veja a seção Parando o bloco switch.

O corpo de cada case deve conter pelo menos uma declaração executável. Não é válido escrever o seguinte código, porque o primeiro case está vazio:

Ao contrário do comando switch em C, este switch não corresponde a ambos "a" e "A". Em vez disso, ele dispara um erro de tempo de compilação que o case "a" não contém instruções executáveis. Esta abordagem evita um declínio acidental de um case para outro e faz com que o código seja mais seguro seja mais claro em sua intenção.

Para fazer um comando switch com um único bloco case que trate ambos "a" e "A", combine os dos valores em um case composto, separando os valores com vírgulas.

Por questões de legibilidade, um case composto também pode ser escrito em mais de uma linha. Para obter informações sobre cases compostos, veja a seção Cases Compostos.

Nota

Para obter o comportamento de fallthrough ao final de um bloco case em particular, use o comando fallthrough, como descrito na seção Fallthrough.

Matching com intervalos

Quando checamos um valor dentro de um switch e ele cai em um bloco case, essa ação é chamada de matching. Os valores dos blocos case em um switch podem ser checados através de um intervalo, este exemplo usa intervalos numéricos para fornecer uma linguagem natural de contagem para números de qualquer tamanho:

No exemplo acima, a constante approximateCount é avaliada em um comando switch. Cada bloco case compara esse valor com um número ou um intervalo. Como o valor de approximateCount cai entre 12 e 100, a constante naturalCount recebe o valor "dozens of", e a execução é transferida para fora do comando switch.

Tuplas

Você pode usar tuplas para testar vários valores no mesmo comando switch. Cada elemento da tupla pode ser testado em relação com um valor ou intervalo de valores. Alternativamente, use o caractere de underscore _, também conhecido como wildcard para corresponder a qualquer valor possível.

O exemplo abaixo considera um ponto (x, y) expressado como uma simples tupla (Int, Int) e categoriza ela em um gráfico mostrado abaixo:

O comando switch determina se o ponto está na origem (0, 0), no eixo vermelho x, no eixo laranja y , dentro da caixa azul 4 por 4 ou fora da caixa .

Ao contrário da linguagem C, o Swift permite que vários blocos cases considerem o mesmo valor ou valores. Na verdade, o ponto (0, 0) pode dar match com todos os quatro cases neste exemplo. No entanto, se vários matches forem possíveis, o primeiro case que der match será sempre usado. O ponto (0, 0) combinaria o primeiro case (0, 0) e, portanto, todos os outros cases correspondentes seriam ignorados.

Binding de valores

Um case de um switch pode nomear o valor ou valores que ele deu match para que correspondam a constantes ou variáveis temporárias para uso dentro do seu bloco. Esse comportamento é conhecido como binding de valor, porque os valores são vinculados a constantes ou variáveis temporárias ​​dentro do bloco do case.

O exemplo abaixo considera um pont (x, y) expressado como uma tupla do tipo (Int, Int) e categoriza ela em um gráfico mostrado abaixo:

O comando switch determina se o ponto está no eixo vermelho x, no eixo laranja y e, ou em outro lugar (em nenhum dos eixos).

Os três cases declaram placeholders como constantes x e y que temporariamente assumem um ou ambos os valores da tupla anotherPoint. O primeiro case, o case (let x, 0), corresponde a qualquer ponto com um valor y = 0 e atribui o valor de x da tupla para a constante temporária x. Da mesma forma, o segundo case, o case(0, let y), coincide com qualquer ponto com um valor x = 0 e atribui o valor de y da tupla à constante temporária y.

Depois que as constantes temporárias são declaradas, elas podem ser usadas dentro do bloco de código de cada case. Aqui, eles são usados ​​para imprimir a categorização do ponto.

Este comando switch não possui um case default. O case final, case let (x, y), declara uma tupla de duas constantes como placeholders que podem dar match qualquer valor. Como anotherPoint é sempre uma tupla de dois valores, este case corresponde a todos os valores remanescentes possíveis, e um case default não é necessário para tornar a declaração do switch exaustiva.

Where

O comando switch pode usar uma cláusula where para realizar checagens adicionais. O exemplo abaixo categoriza um ponto (x, y) no seguinte gráfico:

O comando switch determina se o ponto está na linha diagonal verde onde x == y, na linha diagonal roxa onde x == -y, ou nenhum deles.

Os três cases declaram as constantes x e y como placeholders que temporariamente assumem os dois valores da tupla yetAnotherPoint. Essas constantes são usadas como parte de uma cláusula where, para criar um filtro dinâmico. O case corresponde ao valor atual de point somente se a condição da cláusula where for true para esse valor.

Como no exemplo anterior, o case final corresponde a todos os valores remanescentes possíveis e, portanto, um case default não é necessário para tornar a declaração do switch exaustiva.

Cases compostos

Múltiplos cases que compartilham o mesmo bloco de código podem ser combinados escrevendo vários padrões depois do comando case, com uma vírgula entre cada padrão. Se qualquer um dos padrões for atingido (der matching), então o case inteiro é consierado como matched. Os padrões podem ser escritos com mais de uma linha se a lista de padrões for muito grande, por exemplo:

O primeiro case acima corresponde às cinco vogais em minúsculas na língua inglesa. Da mesma forma, o segundo case corresponde a todas as consoantes inglesas em minúsculas. Finalmente, o case default corresponde a qualquer outro caractere.

Os cases compostos também podem incluir bindings de valor. Todos os padrões de um case composto devem incluir o mesmo conjunto de bindings de valor e cada binding deve ter um valor do mesmo tipo de todos os padrões no case composto. Isso assegura que, independentemente de qual parte do case composto acontecer o matching, o código no corpo do case pode sempre acessar um valor do binding e que o valor sempre tem o mesmo tipo.

O case acima tem dois padrões: (let distance, 0) que corresponde aos pontos no eixo x e (0, let distância) que corresponde a pontos no eixo y. Ambos os padrões incluem um binding para distance e distance é um número inteiro em ambos os padrões - o que significa que o código no corpo do case pode sempre acessar o valor de distance.

Comandos de transferência de controle

Os comandos de transferência de controle mudam a ordem em que seu código é executado trasferindo o controle de uma parte do código para outra. O Swift possui cinco comandos de transferência de controle.

  • continue
  • break
  • fallthrough
  • return
  • throw

Os comandos continue, break e fallthrough são descritos nas seções abaixo. O comando return é descrito na seção Funções e o comando throw é descrito na seção Propagando erros usando funções que lançam exceções.

Continue

O comando continue diz para um loop parar o que está fazendo e recomeçar da próxima iteração do loop. Ele diz, "Eu terminei o que estava fazendo nessa iteração, comece outra" sem sair do loop completamente. O exemplo abaixo remove todas as vogais e espaços de uma string para criar um puzzle criptografado.

O codigo acima usa o comando continue sempre que uma vogal ou espaço é encontrado, causando a interrupção imediata da atual iteração e pulando diretamente para começar a proxima iteração.

Break

O comando break encerra imediatamente a execução de um comando de fluxo de controle por inteiro. Ele pode ser usado dentro de um comando switch ou algum loop quando você quer cancelar a execução deles antecipadamente quando algum dado for encontrado.

Break em um comando de loop

Quando usado dentro de um comando de loop, o break termina a execução do loop imediatamente e transfere o fluxo do código para depois do fechamento do bloco do loop pelas chaves (}). Nenhum código da atual iteração do loop é executado e nenhuma outra iteração é começada.

Break em um comando switch

Quando usado dentro de um comando switch, o break faz com que o switch termine sua execução imediatamente e transfere o fluxo do código para depois do fechamento do comando switch pelas chaves (}).

Este comportamento pode ser usado para dar match e ignorar algum bloco case que não seja necessário para sua lógica. Como o switch do Swift é um comando exaustivo (precisa tratar todas as possibilidades de cases possíveis) e não permite cases vazios, em alguns casos é necessário simplesmente dar match e ignorar um bloco case para deixar suas inteções explícitas para o compilador. Você consegue fazer isso escrevendo um comando break como único comando dentro do corpo do bloco case que você quer ignorar. Quando ocorrer um match para esse case, o comando break dentro do case faz com que a execução do bloco switch termine imediatamente.

Nota

Um bloco case que contém somente um comentário dispara um erro em tempo de compilação. Comentários não são comandos e não fazem com que um case seja ignorado. Sempre use um comando break para ignorar um case de um switch.

O exemplo abaixo escolhe um valor do tipo Character e determina se ele representa um símbolo númerico em uma das quatro línguas. Para o código ficar mais curto, vários valores são abordados em um único bloco case.

Este exemplo verifica a constante numberSymbol para determinar se é um símbolo latino, árabe, chinês ou tailandês para os números de 1 a 4. Se acontecer um mach, um dos cases seta o valor de uma variável Int? opcional chamada possibleIntegerValue para um valor inteiro apropriado.

Depois que o comando switch completar sua execução, o exemplo usa o binding opcional para determinar se um valor foi encontrado. A variável possibleIntegerValue tem um valor inicial implícito nil em virtude de ser um tipo opcional e, portanto, o binding opcional será bem-sucedido se possibleIntegerValue for setado para um valor real por um dos quatro primeiros cases.

Como não é prático listar todos os valores de caracteres possíveis no exemplo acima, um case default lida com todos os caracteres que não são compatíveis. Este case default não precisa executar nenhuma ação e, portanto, é escrito com um único comando break em seu corpo. Assim que o case default realizar um match com algum valor, o comando break termina a execução do switch e a execução do código continua da instrução if let.

Fallthrough

No Swift, os comandos switch não caem de case em case. Ou seja, a declaração completa do switch conclui sua execução assim que o primeiro case correspondente for concluído. Em contraste, a linguagem C exige que você insira um comando break de forma explícita no final de cada case para evitar falhas. Evitar esse comportamento por padrão significa que o switch do Swift é muito mais conciso e previsíveil do que suas contrapartes em C e, portanto, evitam a execução de vários cases por engano.

Se você precisar do comportamento de fallthrough como na linguagem C, você pode optar por adicionar esse comportamento case por case adicionando o comando fallthrough. O exemplo abaixo usa o comando fallthrough para criar uma descrição textual de um número.

Este exemplo declara uma nova variável do tipo String chamada description com um valor inicial. O switch então considera o valor de uma variável chamada integerToDescribe para verificar se o valor dela é um dos números primos na lista e então adicionar uma descrição para ele informando que ele é um número primo. Por fim, ele usa o comando fallthrough para cair para o case default também. O case default então adiciona uma descrição extra e termina a execução do bloco switch.

A menos que o valor da variável intergerToDescribe esteja na lista conhecida de números primos, ele não será tratado pelo primeiro case. Como não há outro case em específico, integerToDescribe é tratado pelo case default.

Depois que o comando switch termina sua execução, a descrição do número é impressa usando a função print(_:separator:terminator:). Neste exemplo, o número 5 é corretamente identificado como um número primo.

Nota

O comando fallthrough não analisa o bloco case em que ele será executado, ele simplesmente faz a execução do código cair diretamente para o próximo bloco case (ou o case default), assim como o comportamento padrão da linguagem C.

Comandos com apelidos

No Swift, você pode aninhar loops e comandos condicionais dentro de outros loops e comandos condicionais para criar estruturas de fluxo complexas. No entanto, loops e comandos condicionais podem usar o comando break para finalizar sua execução prematuramente.Portanto, às vezes é útil ser explícito sobre qual loop ou comando condicional você deseja que um break encerre. Da mesma forma, se você tiver vários loops aninhados, pode ser útil ser explícito sobre qual loop o comando continue deve afetar.

Para alcançar esses objetivos, você pode marcar um comando de loop ou um comando condicional com um apelido antes da declaração. Com um comando condicional, você pode usar um apelido com o comando break para encerrar a execução do bloco apelidado. Com um comando de loop, você pode usar um apelido com os comandos break ou continue para finalizar ou continuar a execução do comando apelidado.

Um comando com apelido é criado colocando um nome na mesma linha que a palavra-chave introdutora do comando, seguido de dois pontos. Aqui está um exemplo desta sintaxe para um loop while, embora o princípio seja o mesmo para todos os loops e comando switch:

O exemplo acima usa os comandos break e continue com um loop while com apelido para uma versão adaptada do jogo Snakes and Ladders que você viu nos exemplos acima. Dessa vez, o jogo tem uma regra extra:

  • Para vencer, você deve parar exatamente no quadrado 25.

Se uma rolagem de dado em particular te levar além do quadrado 25, você deve rodar o dado novamente até você receber o número necessário para te levar até o quadrado 25. O tabuleiro do jogo é o mesmo que antes:

Os valores de finalSquare, board, square e diceRoll são inicializados do mesmo jeito que antes:

Essa versão do jogo usa um loop while e um comando switch para implementar a lógica do jogo. O loop while é um comando com apelido chamado gameLoop para indicar que ele é o loop principal do jogo.

A condição do loop while é while square != finalSquare e para atingir essa condição, você deve estar exatamente no quadrado 25.

O dado é rolado no começo de cada iteração do loop. Ao invés de mover o jogador imediatamente, o loop usa o comando switch para considerar o resultado da jogada e determinar se o movimento é permitido.

  • Se a rolagem do dado vai mover o jogador até o quadrado final, o jogo termina. O comando break gameLoop transfere o fluxo do código para a primeira linha fora do loop while, que termina o jogo.
  • Se a rolagem do dado levar o jogador além do quadrado final, a jogada é invalida e o jogador precisa rolar o dado novamente. O comando continue gameLoop termina a execução da atual iteração do loop while e começa a próxima iteração do mesmo.
  • Em todos os outros casos, a rolagem do dado é um movimento válido. O jogador se move o número de quadrados equivalente a diceRoll, e a lógica do jogo procura por escadas ou cobras. O loop então termina e o controle retorna ao comando while para verificar se outro turno será necessário.

Nota

Se o comando break acima não usasse o apelido gameLoop, ele iria parar o comando switch ao invés do loop while. Usando o apelido gameLoop, fica claro qual bloco de código ele irá terminar.

Não é estritamente necessário usar o apelido gameLoop quando usamos o comando continue gameLoop para pular para a próxima iteração do loop. Só existe um loop no código e portanto não há ambiguidade em qual parte do código o comando continue irá afetar. Entretanto não há problemas em usar o apelido gameLoop com o comando continue, pois fazendo isso deixamos o código mais consistente pois já utilizamos o apelido junto com o comando break, tornando a lógica mais clara e fácil de entender.

Saída Antecipada

Um comando guard, assim como um comando if, executa comandos dependendo de um valor booleano de uma expressão. Você pode usar o comando guard para exigir que uma condição seja true para que o código depois do comando guard seja executado. Diferentemente de um comando if, o comando guard sempre tem uma cláusula else. O código dentro da cláusula else é executado se a condição for avaliada como false.

Se a condição dentro do comando guard é satisfeita, a execução do código continua normalmente após o fechamento das chaves. Qualquer variável ou constante que recebem valores usando o binding opcional como parte da condição são disponibilizadas para o resto do bloco de código em que o comando guard aparece.

Se essa condição não for satisfeita, o código dentro do bloco else é executado. Este bloco deve transferir o controle do código para sair desse bloco em que o comando guard aparece. Ele pode fazer isso com um comando de transferência de controle como return, break, continue ou throw. Ou ele pode chamar uma função que não retorna parâmetros, como a função fatalError(_:file:line:).

Usar um comando guard para criar requisitos melhora a legibilidade do seu código, em comparação com o mesmo controle com um comando if. Ele permite que você escreva o código que normalmente é executado sem envolvê-lo em um bloco else, ele também permite que você mantenha o código que lida com a quebra de requisito ao lado do requisito.

Verificando disponibilidade de API

O Swift possui suporte nativo para verificação da disponibilidade das API's nativas, o que garante que você não vai usar uma API que esteja indisponível para um certo dispositivo acidentalmente.

O compilador usa as informações de disponibilidade do SDK para verificar que todas as API's usadas no seu código estão disponíveis no target específico do seu projeto. O Swift dispara um erro em tempo de compilação se você tentar usar uma API que não está disponível.

Você pode usar um comando condicional de disponibilidade com um comando if ou guard para executar um bloco de código dependendo de quais API's estarão disponíveis em tempo de execução. O compilador usa a informação a partir da condição de disponibilidade quando ele verifica se a API para aquele bloco de código está disponível.

A condição de disponibilidade acima especifica que no iOS, o corpo do comando if é executado apenas no iOS 10 e posterior, nos macs, apenas no MacOS 10.12 e posterior. O último argumento, *, é exigido e especifica que em qualquer outra plataforma, o corpo do if executa no minimum deployment target especificado pelo seu target.

Em sua forma geral, a condição de disponibilidade possui uma lista de nomes e versões de plataformas. Você pode usar nomes de plataforma como iOS, macOS, watchOS e tvOS - para a lista completa, veja a seção Atributos de declaração. Além de especificar números de versão maiores, como iOS 8 ou macOS 10.10, você pode especificar números de versões menores, como iOS 8.3 e macOS 10.10.3.

results matching ""

    No results matching ""