Guia do desenvolvedor iOS: do Objective-C ao aprendizado Swift
Publicados: 2022-03-11Em 2008, a Apple anunciou e lançou o iPhone SDK 2.0. Este evento iniciou outra revolução no desenvolvimento de software, e uma nova geração de desenvolvedores nasceu. Eles agora são reconhecidos como desenvolvedores iOS.
Muitos desses desenvolvedores nunca haviam usado Objective-C antes, e esse foi o primeiro desafio que a Apple lançou a eles. Apesar da sintaxe desconhecida e do gerenciamento manual de memória, foi imensamente bem-sucedido, ajudando a preencher a App Store com dezenas de milhares de aplicativos. A Apple melhorou continuamente o Objective-C a cada versão, adicionando blocos e literais, gerenciamento de memória simplificado com contagem automática de referência e muitos outros recursos indicativos de uma linguagem de programação moderna.
E depois de 6 anos melhorando e trabalhando no Objective-C, a Apple decidiu lançar outro desafio aos desenvolvedores. Mais uma vez, os desenvolvedores iOS precisarão aprender uma nova linguagem de programação: Swift . O Swift remove o gerenciamento de ponteiro inseguro e apresenta novos recursos poderosos, mantendo a interação com Objective-C e C.
O Swift 1.0 já é uma plataforma de desenvolvimento estável e forte, que certamente evoluirá de maneiras interessantes nos próximos anos. É um momento perfeito para começar a explorar esta nova linguagem, pois é obviamente o futuro do desenvolvimento iOS.
O objetivo deste tutorial é fornecer aos desenvolvedores do Objective-C uma visão geral rápida dos novos recursos da linguagem Swift, ajudando você a dar o próximo passo e começar a adotar o Swift em seu trabalho diário. Não vou gastar muito tempo explicando Objective-C, e vou assumir que você está familiarizado com o desenvolvimento iOS.
Experimentando Swift vs. Objective-C
Para começar a explorar o Swift, tudo o que você precisa fazer é baixar o XCode da App Store e criar um playground para experimentar. Todos os exemplos mencionados neste artigo são feitos desta forma.
A página inicial do Swift da Apple é a melhor referência para aprender programação Swift. Você achará isso inestimável e, até que esteja totalmente atualizado com o desenvolvimento do Swift, acredito que você voltará aqui com frequência.
Variáveis e Constantes
Declarar uma variável no Swift é feito usando a palavra-chave var
.
var x = 1 var s = "Hello"
Você notará que duas variáveis x
e s
são de tipos diferentes. x
é um Integer, enquanto s
é uma String. Swift é uma linguagem de tipo seguro e deduzirá tipos de variáveis do valor atribuído. Se você deseja tornar seu código mais legível, você pode anotar opcionalmente o tipo da variável:
var y: Int y = 2
Constantes são semelhantes, mas você as declara usando let
em vez de var
. O valor de uma constante não precisa ser conhecido em tempo de compilação, mas você deve atribuir um valor a ela exatamente uma vez.
let c1 = 1 // Constant known at compile time var v = arc4random() let c2 = v // Constant known only at run time
Como o nome sugere, eles são imutáveis, portanto, o código a seguir causará um erro em tempo de compilação.
let c = 1 c = 3 // error
Outros tipos também podem ser declarados como constantes. Por exemplo, o código a seguir declara um array como uma constante e, se você tentar modificar qualquer um dos elementos, o compilador Swift reportará um erro:
var arr2 = [4, 5, 6] arr2[0] = 8 print (arr2) // [8, 5, 6] let arr = [1, 2, 3] a[0] = 5 // error
Opcionais
As constantes precisam ser inicializadas ao declará-las e as variáveis precisam ser inicializadas antes do uso. Então, onde está o equivalente nil
do Objective-C? Swift introduz valores opcionais . Os valores opcionais podem ter um valor ou ser nil
. Se você der uma olhada no código a seguir, notará que x
recebeu um valor Optional
de 2014
. Isso significa que o compilador Swift estava ciente de que x
também pode ser nil
.
var s = "2014" var x = s.toInt() print(x) // Optional(2014)
Se você fizer uma alteração neste código e atribuir o valor "abc"
a s
, que não pode ser convertido em um Integer, você notará que x
agora é nil
.
var s = "abc" var x = s.toInt() print(x) // nil
O tipo de retorno da função toInt()
é Int?
, que é um Int opcional . Vamos tentar chamar uma função padrão em x
:
var x = "2014".toInt() print(x.successor()) // error
O compilador sinaliza um erro, pois x
é opcional e pode ser nil . Temos que testar x
primeiro e garantir que a função successor
seja invocada em um número real, e não em um valor nil
:
var x = "2014".toInt() if x != nil { print(x!.successor()) // 2015 }
Observe que temos que desembrulhar x
acrescentando um ponto de exclamação (!) . Quando temos certeza de que x
contém um valor, podemos acessá-lo. Caso contrário, obteremos um erro de tempo de execução. Também podemos fazer o que Swift chama de ligação opcional , convertendo o opcional em uma variável não opcional
let x = "123".toInt() if let y = x { print(y) }
O código na instrução if
só será executado se x
tiver um valor e o atribuirá a y
. Observe que não precisamos desembrulhar y
, seu tipo não é opcional, pois sabemos que x
não é nil
.
Verifique o tutorial Swift da Apple para ler mais detalhes sobre opcionais e recursos interessantes, como encadeamento opcional
Interpolação de String
Em Objective-C, a formatação de strings geralmente é feita com o método stringWithFormat:
::
NSString *user = @"Gabriel"; int days = 3; NSString *s = [NSString stringWithFormat:@"posted by %@ (%d days ago)", user, days];
O Swift possui um recurso chamado interpolação de strings para fazer o mesmo, mas é mais compacto e fácil de ler:
let user = "Gabriel" let days = 3 let s = "posted by \(user) \(days) ago"
Você também pode usar expressões:
let width = 2 let height = 3 let s = "Area for square with sides \(width) and \(height) is \(width*height)"
Para saber mais sobre a interpolação de strings do Swift e outros novos recursos, acesse aqui.
Funções
A definição de função em Swift é diferente de C. Uma definição de função de exemplo está abaixo:
func someFunction(s:String, i: Int) -> Bool { ... // code }
As funções Swift são tipos de primeira classe . Isso significa que você pode atribuir funções a variáveis, passá-las como parâmetros para outras funções ou fazê-las retornar tipos:
func stringLength(s:String) -> Int { return countElements(s) } func stringValue(s:String) -> Int { if let x = s.toInt() { return x } return 0 } func doSomething(f:String -> Int, s:String) -> Int { return f(s).successor() } let f1 = stringLength let f2 = stringValue doSomething(f1, "123") // 4 doSomething(f2, "123") // 124
Novamente, Swift infere os tipos de f1
e f2
( String
-> Int
), embora pudéssemos defini-los explicitamente:
let f1:String -> Int = stringLength
As funções também podem retornar outras funções:
func compareGreaterThan(a: Int, b: Int) -> Bool { return a > b } func compareLessThan(a: Int, b: Int) -> Bool { return a < b } func comparator(greaterThan:Bool) -> (Int, Int) -> Bool { if greaterThan { return compareGreaterThan } else { return compareLessThan } } let f = comparator(true) println(f(5, 9))
Um guia para funções no Swift pode ser encontrado aqui.
Enumerações
Enumerações em Swift são muito mais poderosas do que em Objective-C. Como estruturas Swift, elas podem ter métodos e são passadas por valor:
enum MobileDevice : String { case iPhone = "iPhone", Andro, WP8 = "Windows Phone8", BB = "BlackBerry" func name() -> String { return self.toRaw() } } let m = MobileDevice.Android print(m.name()) // "Android"
Ao contrário do Objective-C, as enumerações do Swift podem atribuir Strings, caracteres ou floats como valores para cada membro, além de inteiros. O conveniente método toRaw()
retorna o valor atribuído a cada membro.
As enumerações também podem ser parametrizadas:
enum Location { case Address(street:String, city:String) case LatLon(lat:Float, lon:Float) func description() -> String { switch self { case let .Address(street, city): return street + ", " + city case let .LatLon(lat, lon): return "(\(lat), \(lon))" } } } let loc1 = Location.Address(street: "2070 Fell St", city: "San Francisco") let loc2 = Location.LatLon(lat: 23.117, lon: 45.899) print(loc1.description()) // "2070 Fell St, San Francisco" print(loc2.description()) // "(23.117, 45.988)"
Mais informações sobre enumerações estão disponíveis aqui.

Tuplas
As tuplas agrupam vários valores em um único valor composto. Os valores dentro de uma tupla podem ser de qualquer tipo e não precisam ser do mesmo tipo uns dos outros.
let person = ("Gabriel", "Kirkpatrick") print(person.0) // Gabriel
Você também pode nomear os elementos de tupla individuais:
let person = (first: "Gabriel", last: "Kirkpatrick") print(person.first)
Tuplas são extremamente convenientes como tipos de retorno para funções que precisam retornar mais de um valor:
func intDivision(a: Int, b: Int) -> (quotient: Int, remainder: Int) { return (a/b, a%b) } print(intDivision(11, 3)) // (3, 2) let result = intDivision(15, 4) print(result.remainder) // 3
Ao contrário do Objective-C, o Swift suporta correspondência de padrões em uma instrução switch:
let complex = (2.0, 1.1) // real and imaginary parts switch complex { case (0, 0): println("Number is zero") case (_, 0): println("Number is real") default: println("Number is imaginary") }
No segundo caso, não nos importamos com a parte real do número, então usamos um _
para corresponder a qualquer coisa. Você também pode verificar condições adicionais em cada caso. Para isso, precisamos vincular os valores do padrão às constantes:
let complex = (2.0, 1.1) switch complex { case (0, 0): println("Number is zero") case (let a, 0) where a > 0: println("Number is real and positive") case (let a, 0) where a < 0: println("Number is real and negative") case (0, let b) where b != 0: println("Number has only imaginary part") case let (a, b): println("Number is imaginary with distance \(a*a + b*b)") }
Observe como precisamos vincular apenas os valores que usaremos na comparação ou na instrução case.
Para ler mais sobre tuplas, clique aqui.
Classes e Estruturas
Ao contrário do Objective-C, o Swift não exige que você crie interfaces e arquivos de implementação separados para classes e estruturas personalizadas. À medida que você aprende Swift, você aprenderá a definir uma classe ou estrutura em um único arquivo, e a interface externa para essa classe ou estrutura é automaticamente disponibilizada para outro código usar.
Definindo classes
As definições de classe são muito simples:
class Bottle { var volume: Int = 1000 func description() -> String { return "This bottle has \(volume) ml" } } let b = Bottle() print(b.description())
Como você pode ver, declaração e implementação estão no mesmo arquivo . Swift não usa mais arquivos de cabeçalho e implementação. Vamos adicionar um rótulo ao nosso exemplo:
class Bottle { var volume: Int = 1000 var label:String func description() -> String { return "This bottle of \(label) has \(volume) ml" } }
O compilador reclamará porque label é uma variável não opcional e não manterá um valor quando um Bottle for instanciado. Precisamos adicionar um inicializador:
class Bottle { var volume: Int = 1000 var label:String init(label:String) { self.label = label } func description() -> String { return "This bottle of \(label) has \(volume) ml" } }
Ou podemos usar o tipo Optional
para uma propriedade, que não deve ser inicializada. No exemplo a seguir, transformamos o volume
em um Optional Integer
:
class Bottle { var volume: Int? var label:String init(label:String) { self.label = label } func description() -> String { if self.volume != nil { return "This bottle of \(label) has \(volume!) ml" } else { return "A bootle of \(label)" } } }
Estruturas
A linguagem Swift também possui structs
, mas elas são muito mais flexíveis do que em Objective-C. O tutorial de código a seguir define um struct
:
struct Seat { var row: Int var letter:String init (row: Int, letter:String) { self.row = row self.letter = letter } func description() -> String { return "\(row)-\(letter)" } }
Assim como as classes em Swift, as estruturas podem ter métodos, propriedades, inicializadores e estar em conformidade com protocolos. A principal diferença entre classes e estruturas é que classes são passadas por referência, enquanto structs são passadas por valor .
Este exemplo demonstra a passagem de classes por referência:
let b = Bottle() print(b.description()) // "b" bottle has 1000 ml var b2 = b b.volume = 750 print(b2.description()) // "b" and "b2" bottles have 750 ml
Se tentarmos um caso semelhante com struct
, você notará que as variáveis são passadas por valor:
var s1 = Seat(row: 14, letter:"A") var s2 = s1 s1.letter = "B" print(s1.description()) // 14-B print(s2.description()) // 14-A
Quando devemos usar struct
e quando devemos usar class
? Como em Objective-C e C, use structs quando precisar agrupar alguns valores e esperar que eles sejam copiados em vez de referenciados. Por exemplo, números complexos, pontos 2D ou 3D ou cores RGB.
Uma instância de uma classe é tradicionalmente conhecida como um objeto. No entanto, as classes e estruturas do Swift são muito mais próximas em funcionalidade do que em outras linguagens, e muitas funcionalidades podem ser aplicadas a instâncias de uma classe ou de um tipo de estrutura. Por causa disso, o termo mais geral usado na referência do Swift é instance
, que se aplica a qualquer um desses dois.
Aprenda o básico das classes e estruturas do Swift aqui.
Propriedades
Como vimos anteriormente, as propriedades em Swift são declaradas com a palavra-chave var
dentro de uma classe ou definição de struct. Também podemos declarar constantes com uma instrução let
.
struct FixedPointNumber { var digits: Int let decimals: Int } var n = FixedPointNumber(digits: 12345, decimals: 2) n.digits = 4567 // ok n.decimals = 3 // error, decimals is a constant
Lembre-se também de que as propriedades de classe são fortemente referenciadas, a menos que você as prefixe com a palavra-chave weak
. No entanto, existem algumas sutilezas com propriedades não opcionais fracas, então leia o capítulo de contagem automática de referências no guia Swift da Apple.
Propriedades computadas
Propriedades computadas na verdade não armazenam um valor. Em vez disso, eles fornecem um getter e um setter opcional para recuperar e definir outras propriedades e valores indiretamente.
O código a seguir fornece uma amostra de um sign
de valor calculado:
enum Sign { case Positive case Negative } struct SomeNumber { var number:Int var sign:Sign { get { if number < 0 { return Sign.Negative } else { return Sign.Positive } } set (newSign) { if (newSign == Sign.Negative) { self.number = -abs(self.number) } else { self.number = abs(self.number) } } } }
Também podemos definir propriedades somente leitura apenas implementando um getter:
struct SomeNumber { var number:Int var isEven:Bool { get { return number % 2 == 0 } } }
Em Objective-C, as propriedades geralmente são apoiadas por uma variável de instância, declarada explicitamente ou criada automaticamente pelo compilador. Em Swift, por outro lado, uma propriedade não possui uma variável de instância correspondente . Ou seja, o armazenamento de apoio de uma propriedade não pode ser acessado diretamente. Suponha que temos isso em Objective-C
// .h @interface OnlyInitialString : NSObject @property(strong) NSString *string; @end // .m @implementation OnlyInitialString - (void)setString:(NSString *newString) { if (newString.length > 0) { _string = [newString substringToIndex:1]; } else { _string = @""; } } @end
Como, em Swift, as propriedades computadas não possuem um backing store, precisamos fazer algo assim:
class OnlyInitialString { var initial:String = "" var string:String { set (newString) { if countElements(newString) > 0 { self.initial = newString.substringToIndex(advance(newString.startIndex, 1)) } else { self.initial = "" } } get { return self.initial } } }
As propriedades são explicadas com mais detalhes aqui
Continua
Há muitas coisas novas e importantes para aprender no Swift, como Generics, interação com bibliotecas Objective-C, closures, encadeamento opcional e sobrecarga de operadores. Um único tutorial não pode descrever completamente uma nova linguagem, mas não tenho dúvidas de que muito mais será escrito sobre o aprendizado de programação em Swift. No entanto, acredito que esta leitura rápida ajudará muitos desenvolvedores de Objective-C, que não conseguiram encontrar tempo e aprender detalhes da linguagem Swift, a entrar no caminho certo e deixar o pássaro Swift levá-los a novas alturas.