Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Swift
Code

Introdução à Swift: Parte 2

by
Difficulty:BeginnerLength:LongLanguages:

Portuguese (Português) translation by Erick Patrick (you can also view the original English article)

No primeiro artigo dessa série sobre Swift, falamos sobre a filosofia dela, demos uma olhada na sua sintaxe e destacamos diferenças chaves em relação a Objective-C. Nesse artigo, continuaremos a explorar a sintaxe da Swift. Também aprenderemos sobre opcionais e como administração de memória funciona em Swift.

1. Condicionais & Laços

If

Declarações if são idênticas em Swift e Objective-C, exceto por duas diferenças sutis:

  • Parêntese ao redor da variável da condição são opcionais
  • chaves são requeridas

Essas são, basicamente as únicas diferenças para as declarações if de Objective-C.

Séries

Como vimos no primeiro artigo, Swift inclui dois operadores de alcance, ..< e ..., para especificar valores de séries. Eles são o operador de série semi-fechada e o operador de série fechada.

Um série semi-fechada, tal qual 1..<5, representa os valores 1, 2, 3 e 4, excluindo o 5. Uma série fechada, como 1...5, representa os valores 1, 2, 3, 4, e inclui o 5.

Séries podem ser usadas em laços for, subscript de array e até declarações switch. Vejamos alguns exemplos:

Switch

Declarações switch são muito mais poderosas na Swift que em Objective-C. Em Objective-C, o resultado da expressão de uma declaração switch precisa ser um inteiro e os valores de cada declaração case deve ser uma constante ou expressão de constante. Não é assim na Swift. Nela, as declarações case podem ser de qualquer tipo, incluindo séries.

Na Swift, switch não precisa de break e ele não passa automaticamente de um caso para outro. Ao criar declarações switch, é preciso cuidado pois todas as condições precisam ser lidadas pelos casos. Falhar nisso, resultará em erro de compilação. Uma forma de cobrir todas as condições é incluir uma declaração de caso default.

Eis um exemplo de um switch com casos em String:

Na Swift, declarações case não passam por padrão. Isso é uma decisão de design deliberada para evitar erros. Se um caso específico precisas passar, podemos usar a palavra-chave fallthrough para indicar para o compilador.

E não para aí. Swift adiciona dois recurso ao switch, ligação de valores e cláusula where. Ligação de valores é usado com as palavras-chave case let para ligar uma constante a um caso. A cláusula where adiciona uma condição extra ao caso usando a palavra-chave where.

Esses dois conceitos são melhores explicados em exemplos. O código abaixo mostra como ligação de valores funciona.

O primeiro caso, case (let x, 0) casará quando yaxis for igual a 0 e xaxis qualquer valor, além de atribuir seu valor a x para uso dentro do caso.

Eis um exemplo da cláusula where em ação.

2. Funções & Clausuras

Funções

Definir funções em clausuras é fácil em Swift. Desenvolvedores de Objective-C as conhecem melhores como funções e blocos.

Na Swift, parâmetros de função podem ter valores padrão, reminiscente de linguagens de script, como PHP e Ruby.

A sintaxe para funções é como a seguir:

Para escrever a função sayHello que tem o parâmetro name do tipo String e returna um Bool quando bem sucedida, escrevemos o seguinte:

Para passar um valor padrão para o parâmetro name, a implementação da função deveria ser assim:

Um recurso inexistente em Objective-C são as tuplas. Em Swift, funções podem retornar valores múltiplos na forma de tuplas. Tuplas são consideradas uma única variável, significando que podemos passá-las como qualquer variável.

Tuplas são fáceis de usar. Na verdade, já trabalhamos com tuplas no artigo anterior quando enumeramos um dicionário. No próximo trecho de código, o par chave/valor é uma tupla.

Como elas são usadas como nos beneficiamos delas? Vejamos outro exemplo. Modifiquemos a função sayHello acima para retornar um booleano quando bem sucedido, assim como a mensagem em si. Para tanto, retornamos uma tupla, (Bool, String). A versão atualizada de sayHello parece com isso:

Tuplas estão na lista de desejos de vários programadores de Objective-C há tempos.

Outro recurso legal das tuplas é que podemos nomear as variáveis retornadas. Se revisitarmos o exemplo anterio e dermos nomes às variáveis da tupla, teremos o seguinte:

Isso significa que, ao invés de definir uma constante separada para cada elemento retornada da tupla, podemos acessar os elementos da tupla retornada usando a notação de ponto como visto acima, status.success e status.greeting.

Clausuras

Clausuras em Swift são o mesmo que blocos em Objective-C. Elas podem ser definidas em linha, passadas como parâmetro ou retornadas por funções. Usamo-nas exatamente como usamos blocos em Objective-C.

Definir clausuras é fácil. Na verdade, uma função é um tipo especial de clausura. Logo, faz todo sentido que uma clausura pareça com uma função.

Clausuras são tipos de primeira-classe, ou seja, podem ser passadas para e retornadas de funções como qualquer outro tipo, como Int, String, Bool, etc. Ela são, essencialmente, blocos de código que podemos invocar depois e ter acesso ao escopo que elas definiras.

Criar uma clausura sem nome é tão simples quanto envolver um bloco de código em chaves. Os parâmetros e tipo de retorno da clausura são separados do corpo dela, com a palavra-chave in.

Digamos que queremos definir uma clausura que retorne true se um número é par, então a clausura seria algo assim:

A clausura isEven receber um Int como parâmetro único e retorna um Bool. O tipo da clausura é (number: Int) -> Bool ou (Int -> Bool). Podemos invocar isEven em qualquer lugar do código do mesmo jeito que blocos de código em Objective-C.

Para passar uma clausura desse tipo como parâmetro de uma função, usamos o tipo da clausura na definição da função:

No exemplo acima, o parâmetro verifier de verifyIfEven é uma clausura que passamos para a função.

3. Classes & Estruturas

Classes

É hora de falar das bases da programação orientada a objetos, as classes. Classes, como mencionado antes, são definidas em um arquivo único de implementação com extensão .swift. Declarações de propriedade e métodos são definidas lá.

Criamos uma classe com a palavra-chave class seguida do nome da classe. A implementação da classe é envolvida por chaves. Como em Objective-C, a convenção de nomeação de classes é usar iniciar com letra maiúscula.

Para criar uma instância de Hotel, escrevemos:

Na Swift, não é preciso invocar init nos objetos, ele já é chamado automaticamente por nós.

Herança de classe segue o mesmo padrão de Objective-C, um dois-pontos separa o nome da classe de sua super-classe. No exemplo abaixo, Hotel herda de BigHotel.

Como em Objective-C, usamos a notação de ponto para acessas propriede do objeto. Contudo, Swift também usa a notação de ponto paa invocar métodos de classe e instância, como abaixo.

Propriedades

Outra diferença em relação a Objective-C é que Swift não distingue em variáveis de instância (ivars) e propriedades. Uma variável de instância é uma propriedade.

Declarar uma propriedades é como definir uma variável ou constante, usando var e let. A única diferença é o contexto que elas são definidas, isso é, o contexto de uma classe.

No exemplo acima, rooms é um valor imutável, uma constante, com valor 10 e fullRooms é uma variável com valor inicial 0 que podemos mudar depois. As propriedades devem ser inicializadas quando declaradas. A única excssão é quando são opcionais, que discutiremos já.

Propriedades Computadas

A Swift também define propriedades computadas. Nada mais são que getter e setter que não guardam valores. Como os nomes indicam, são computadas ou avalidadas em execução.

Abaixo temos um exemplo de propriedade computada. Alteramos rooms para var no resto dos exemplos. Veremos já o porque.

Como description é apenas de leitura e tem apenas uma declaração return, podemos omitir a palavra-chave get e as chaves e apenas usar o return. É uma abreviação e é o que usaremos pelo resto do tutorial.

Também podemos definir propriedades de leitura e escrita. Em Hotel, queremos uma propriedade emptyRooms que obtem o número de quartos livres no hotel, mas também queremos atualizar fullRooms ao ajustar emptyRooms. Fazemo isso através da palavra-chave set, mostrada abaixo.

No setter emptyRooms, a constante newValue nos é dada para representar o valor passado pelo setter. Também é importante notar que propriedades computadas são sempre declaradas como variáveis, usando var, porque seus valores computados podem mudar.

Métodos

Já cobrimos funções mais cedo no artigo. Métodos nada mais são que funções atreladas a um tipo, como uma classe. No exemplo a seguir, implementamos um método de instância, bookNumberOfRooms, em Hotel.

Inicializadores

O inicializador padrão das classes é init. Nela, configuramos os valores iniciais da instância criada.

Por exemplo, se precisamos de uma subclasse de Hotel com 100 quartos, então precisamos inicializar a propriedade rooms com 100. Lembremo-nos que alteramos rooms de uma constante para uma variável logo mais cedo. O motivo disso é que não podemos alterr constantes herdadas em uma subclasse, apenas variáveis herdadas podem mudar.

Inicializadores também podem alterar parâmetos. O exemplo a seguir mostra como funciona.

Sobrescrevendo Métodos e Propriedades Computadas

É uma das coisas mis legais em Swift. Em Swift, uma classe pode sobrescrever tanto métodos como propriedades computadas. Para isso, usamos override. Sobrescrevamos description na classe CustomHotel:

O resultado é que description retornar o retorno do método description da superclasse com a "Howdy!" anexada a ele.

O mais legal de sobrescrever métodos e propriedades computadas é a palavra-chave override. Quando o compilador a vê, ele verifica se a superclasse implementa o método sendo sobrescrito. O compilador também verifica se a propriedade e métodos de uma classe estão em conflito com as propriedades e métodos herdados na árvore da herança.

Por um erro de digitação no método sobrescrito, podemos passar horas tentando descobrir o problema. Em Swift, o compilador dirá exatamente o que há de errada na situação.

Estruturas

Estruturas, definidas com a palavra-chave struct, são mais poderosas em Swift que em C ou Objective-C. Em C, estruturas definem apenas valores e ponteiros. Na Swift também é assim, mas também suportam métodos e propriedades computadas.

Qualquer coisa que fazemos com classe, podemos com estruturas, com duas diferenças importantes:

  • estruturas não suportam herança como classes
  • estruturas são passadas por valor enquanto classes por referência

Eis alguns exemplos de estruturas em Swift:

4. Opcionais

Solução Para Um Problema

Opcionais são um novo conceito se vier do Objective-C. Elas resolvem um problema que programadores se deparam. Quando acessamos uma variável que não temos certeza de seu valor, retornamos um indicador, conhecido como sentinela, para indicar que o que foi retornado não é um valor. Vejamos com um exemplo do Objective-C:

No exemplo acima, tentamos achar a posição de @"B" em someString. Se for achado, sua localização ou posição é salva em pos. Mas o que acontece se não encontrado?

A documentação diz que rangeOfString: retorna um NSRange com a constante NSNotFound em location. No caso de rangeOfString: a sentinela é NSNotFound. Sentinelas são usadas para indicar que o retorno não é válido.

Em Cocoa, existem vários usso desse conceito, mas o valor do sentinela varia de acordo com o contexto, 0, -1, NULL, NSIntergerMax, INT_MAX, Nil, etc. O problema pra o programador é que devemos lembrar qual sentinela é usado em qual contexto. Se o programador não tomar cuidado, pode confundir um valor válido com um sentinel e vice-versa. Swift resolve esse problema com opcionais. Para citar Brian Lanier "Opcionais são o sentinal que comandarão todos".

Opcionais tem dois estados, nil, que significa que o opcional não tem valor, e um segundo valor, que significa ter um valor válido. Pense neles como um pacote com um indicador que diz se o conteúdo é válido ou não.

Uso

Todos tipos em Swift podem ser opcionais. Definimos um opção adicionando ? após a declaração do tipo:

Atribuímos um valor ao pacote do opcionais do mesmo jeito que a variáveis e constantes.

Lemremo-nos que opcionais são como pacotes. Quando declaramos let someInt: Int?, definimos uma caixa vazia com um valor nil. Ao atribuit 10 ao opcional, a caixa contem o inteiro de valor 10 e seu indicador ou estado torna-se not nil.

Para obter o conteúdo de um opção usamos ! . Devemos ter certeza que o opcional tem um valor válido antes de desembrulhá-lo. Falhando, causará um erro de execução. É assim como acessamos o valor de um opcional:

O padrão acima é tão comum em Swift que podemos simplificar o código acima usando a ligação opcional, if let. Vejamos o código atualizado abaixo.

Opcionais são o único tipo que podem ter o nil. Constantes e variáveis não podem ser inicializados com nil. Isso é parte da política de segurança da Swift, onde todas variáveis e constantes não opcionais devem ter valores.

5. Administração de Memória

Se lembrarmos bem, quando ARC foi introduzido, usávamos strong e weak para definir a relação de objetos. Swift também tem o modelo strong e weak de domínio, mas introduz um novo, unowned. Vejamos cada modelo de domínio de objeto em Swift.

strong

Referências forte são o padrão em Swift. A maior parte do tempo, possuímos o objeto que referenciamos e somos o responsável por manter o objeto referenciado vivo.

Como referências fortes são o padrão, não é preciso manter uma referência forte explicitamente a um objeto, qualquer referência é um referência forte.

weak

Uma referência fraca em Swift indica que a referência aponta para um objeto que não somos responsáveis. É usado principalmente entre dois objetos que não precisam um do outro por perto para continuar seus ciclos de vida.

Tem um porém, contudo. Em Swift, referências fracas sempre devem ser variável com um tipo opcional, porque elas recebem nil quando o objeto referenciado é desalocado. A palavra-chave weak é usada na declaração da variável:

unowned

Referências sem domínio são novas para programdores de Objective-C. Nela, não somos responsáveis pela manutenção do objeto referênciado, assim como nas fracas.

A diferença é que as referências sem domínio não recebem nil quando o objeto referenciado é desalocado. Outra diferença importante para referências fracas é que as sem domínio são definidas como tipos não opcionais.

Referências sem domínio podem ser constantes. Um objeto sem domínio ão existe sem seu dono, assim, uma referência sem domínio nunca será nil. Elas precisão da palavra-chave unowned antes da definição da variável ou constante.

Conclusão

Swift é uma linguagem maravilhosa, bem profunda e cheia de potencial. É legal criar programas nela e remove muito do código base que escrevemos no Objective-C e ainda garantindo que nosso código é seguro.

Recomendamos muito A Linguagem de Programação Swift, disponível de graça na iBook Store da Apple.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.