O documento discute conceitos importantes de opicionais em Swift, como:
1) Opcionais podem representar a ausência de valor e são úteis para representar valores que podem ou não existir;
2) Existem diferentes formas de lidar com valores opcionais, como desempacotamento forçado, vinculação opcional e operador nil coalescing;
3) Valores opcionais podem ser encadeados para acessar propriedades e métodos de forma segura.
3. Disclaimer
Looking forward to next month: I'll be the first and
only guy with 4 years of swift programming
experience :-)
— LATTNER, Chris (@clattner_llvm)
image by http://instagram.com/p/rWyQdUDBhH/
4. Disclaimer
Eu escrevi não mais nos que 30 linhas de código em
Swift a mais dos que as que aparecem nessa
apresentação, não sou mais especialista em Swift do
que vocês.
— PINHEIRO, Tales
image by http://instagram.com/p/rWyQdUDBhH/
5. Disclaimer
Não gosto de boa parte do estilo de código
apresentado aqui, mas ainda não consegui escolher
um bom.
— PINHEIRO, Tales
image by http://instagram.com/p/rWyQdUDBhH/
6. A linguagem Zen
Opcionais - questão existêncial:
— Existe um valor, e é igual a x
ou
— NÃO existe um valor (nenhum MESMO!)
7. nil versus Optional
— nil: "equivalente" em Objective-C, válido apenas
para objetos
— Optional: valido para qualquer tipo
8. nil versus Optional
— nil: "equivalente" em Objective-C, válido apenas
para objetos
— Optional: valido para qualquer tipo
9. Quando usar ?
let possibleNumber = "123"
let convertedNumber = possibleNumber.toInt()
let anotherPossibleNumber = "Hello, World"
let whatIsMyValue = anotherPossibleNumber.toInt()
10. Qual o tipo ?
let possibleNumber = "123"
let convertedNumber = possibleNumber.toInt()
let anotherPossibleNumber = "Hello, World"
let whatIsMyValue = anotherPossibleNumber.toInt()
//possibleNumber = 123, whatIsMyValue=nil
11. Qual o tipo ?
let possibleNumber = "123"
let convertedNumber = possibleNumber.toInt()
let anotherPossibleNumber = "Hello, World"
let whatIsMyValue = anotherPossibleNumber.toInt()
//possibleNumber = 123, whatIsMyValue=nil
//whatIsMyValue: inferida como Int?
12. Qual o tipo ?
let possibleNumber = "123"
let convertedNumber = possibleNumber.toInt()
let anotherPossibleNumber = "Hello, World"
let whatIsMyValue = anotherPossibleNumber.toInt()
//possibleNumber = 123, whatIsMyValue=nil
//whatIsMyValue: inferida como Int?
//convertedNumber: inferida como Int?
13. Definição manual do tipo
var myVar: String?
//compilador atribui automaticamente o valor nil
14. Declarações if e desempacotamento forçado
forced wrapping
//1:
if convertedNumber !=nil {
println("Contem algum valor")
}
//2:
if convertedNumber !=nil {
println("Contem o valor (convertedNumber!)") //eu sei que tem um valor. Use!
}
convertedNumber! : desempacotamento forçado
Erro de runtime se convertedNumber contém nil.
15. Atribuição opcional (optional binding)
//3:
if let actualNumber = convertedNumber {
println("Contem o valor (actualNumber)")
}
else {
println("não foi dessa vez")
} //imprime "123"
//4:
if let maybeOtherNumber = "Hello again" {
println("Contem o valor (maybeOtherNumber)")
}
else {
println("não foi dessa vez")
} //imprime "não foi dessa vez"
16. Desenpacotamento implicito de opcionais
Implictly Unwrapped Optionals
let possibleString: String? = "An optional string."
println(possibleString!) // requires an exclamation mark to access its value
// prints "An optional string."
let assumedString: String! = "An implicitly unwrapped optional string."
println(assumedString) // no exclamation mark is needed to access its value
// prints "An implicitly unwrapped optional string.”
17. Desenpacotamento implicito de opcionais
Implictly Unwrapped Optionals
class MyClass {
var myInt: Int! {
didSet {
println("New Value: (myInt).")
}
}
func doSomethingSlow() {
// a few 7.5 million years later...
myInt = 42 //quando chamado, imprime "New Value: 42"
}
}
var obj = MyClass()
obj.doSomethingSlow()
18. Desenpacotamento implicito de opcionais
Implictly Unwrapped Optionals
Você ainda pode verificar se tem conteúdo:
if obj.myInt != nil {
//do something cool with answer to life, the universe and everything
}
ou
if let verifiedInt = obj.myInt {
//do something cool with answer to life, the universe and everything
}
19. Bool
bool opcional não pode mais ser usado para
comparação
Erro de compilação
var myBool : Bool?
if myBool {
println("falso")
}
else {
println("true")
}
20. Bool
bool opcional não pode mais ser usado para
comparação
Erro de compilação
var myBool : Bool?
if myBool != true {
println("falso")
}
else {
println("true")
}
21. nil coalescing operator
Considere o código:
var a : Int? //implicitamente atribuido valor nil
var b = 0
var c = a != nil ? a! : b
// c possui tipo Int (e não Int?) e valor 0
Xcode 6 beta 5 introduz o atalho:
c = a ?? b
23. nil coalescing operator
Um exemplo mais concreto:
let defaultColorname = "red"
var userDefinedColorName: String? //default igual a nil
var colorNameToUse = userDefinedColorName ?? defaultColorname
//colorNameToUse tem valor "red"
userDefinedColorName = "green"
colorNameToUse = userDefinedColorName ?? defaultColorname
//agora colorNameToUse tem valor "green"
24. Opcionais e subscripts (dicionários)
var hexColors = ["red" : "ff0000", "green" : "00ff00", "blue" : "0000ff"]
var hexForRed = hexColors["red"]
25. Opcionais e subscripts (dicionários)
var hexColors = ["red" : "ff0000", "green" : "00ff00", "blue" : "0000ff"]
var hexForRed = hexColors["red"]
O tipo de retorno também é inferido como "String?"
26. Opcionais e subscripts (dicionários)
var hexColors = ["red" : "ff0000", "green" : "00ff00", "blue" : "0000ff"]
var hexForRed = hexColors["red"]
if let hexForGray = hexColors["gray"] {
// is there 50 shades here?
}
else {
printf("¯_()_/¯)
}
forced unwrap...
27. Opcionais e subscripts (dicionários)
E no caso de remover um valor?
if let removedColor = hexColors.removeValueForKey[grey] {
println(I don't know anymore that red is (removedColor))
}
else {
printf(¯_()_/¯)
//imprime esta mensagem
}
Ou pelo atalho:
hexColors[green] = nil
28. Tuplas opcionais
Podemos ter tuplas com valores opcionais ou tuplas
opcionais:
(Int, Int?)
versus
(Int, Int)?
29. Tuplas opcionais
func parseDate(date: String) - (Int, Int?, Int?) {
comp = date.componentsSeparatedByString(/)
return (comp[0].toInt()!, comp[1].toInt(), comp[2].toInt())
}
— Método toInt() retorna opcional
— toInt()! força o desempacotamento
— função acima sempre retorna uma tupla,
possívelmente com algum dos componentes nil
30. Tuplas opcionais
func minMax(array: [Int]) - (min: Int, max: Int)? {
if array.isEmpty { return nil }
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..array.count] {
if value currentMin { currentMin = value }
else if value currentMax { currentMax = value }
}
return (currentMin, currentMax)
}
31. Enumerações - Raw value
enum WeekDay: Int {
case Sunday = 0,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
let weekDayNumber = WeekDay.Friday.toRaw() //weekDay = 6
32. Enumerações - Raw value
enum WeekDay: Int {
case Sunday = 0, Monday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
}
let weekDayNumber = WeekDay.Friday.toRaw() //weekDay = 5
let isThisAWeekDay = WeekDay.fromRaw(8) //isThisAWeekDay: Int?, valor: nil
33. Propriedades com tipos opcionais
class SurveyQuestion {
var text: String
var response: String?
init(text: String) {
self.text = text
}
}
^vamos dar um exemplo de proprieadade com tipo opcional. Nesse exemplo,
response é definida como uma string opcional. Na inicalização ela tem valor
nil, então terá o valor atribuido posteriormente
Propriedades com tipos opcionais
var questionOfLife = SurveyQuestion(text: What is the answer to life,
the universe and everything?)
questionOfLife.response = Forty two
A propriedade response tem tipo String? e valor
nil até ter um valor atribuido
34. Encadeamento de opcionais
Optional chainging
Processo de acessar propriedades, métodos e índices
em uma contante ou váriável opcional que pode na
verdade conter um nil
É similar a enviar uma mensagem para um objeto nil
em Objective-C, mas pode ser usado com qualquer tipo
35. Encadeamento de opcionais
Optional chainging
Usamos interrogação após o valor opcional, ao invés
de exclamação, porém aqui falha usavemente, ao invés
de gerar erro de runtime
O resultado é sempre do mesmo tipo esperado, mas
empacotado em um opcional
36. Encadeamento de opcionais
Optional chainging
class Residence {
var numberOfRooms = 1
}
class Person {
var residence: Residence?
}
37. Encadeamento de opcionais
Optional chainging
let john = Person()
let numberOfRooms = john.residence!.numberOfRooms
// PAN! - erro de runtime
//mas o código abaixo não tem problema
if let numberOfRooms = john.residence?.numberOfRooms {
println(John's residence has
(numberOfRooms) room(s).)
}
38. Encadeamento de opcionais
Optional chainging
Mesmo com inicialização:
john.residence = Residence()
if let numberOfRooms = john.residence?.numberOfRooms {
println(John's residence has
(numberOfRooms) rooms.)
}//imprime John's residence has 1 room(s)
O tipo ainda é inferido como Int?
39. Encadeamento de opcionais
Optional chainging
class Room {
var name: String
init(name: String) {
self.name = name
}
}
class Address {
var street: String?
var number: Int?
}
40. Encadeamento de opcionais
Optional chainging
class Residence {
var rooms = [Room]()
var numberOfRooms: Int { return rooms.count }
subscript(i: Int) - Room {
get { return rooms[i] }
set { rooms[i] = newValue }
}
func printNumberOfRooms() {
println(The number of rooms is (numberOfRooms))
}
var address: Address?
}
41. Encadeamento de opcionais
Optional chainging
let john = Person()
let residence = Residence()
residence.address = someAddress
residence.rooms.append(Room(name: Kitchem))
john.residence = residence
println(John's residence has
(john.residence?.numberOfRooms) room(s))
//Imprime: John's residence has Optional(1) room(s)
42. Encadeamento de opcionais
Optional chainging
println(John's first room is (john.residence?[0].name))
//Imprime: John's first room is Optional(Kitchem)
john.residence?[0].name = Living Room
println(John's first room is (john.residence?[0].name))
//Imprime: John's first room is Optional(Living Room)
43. Encadeamento de opcionais
Optional chainging
var hexColors = [red : [00, 00, 00],
green : [00, ff, 00],
blue : [00, 00, ff]]
hexColors[red]?[0] = ff
44. Encadeamento de opcionais
Optional chainging
var hexColors = [red : [00, 00, 00],
green : [00, ff, 00],
blue : [00, 00, ff]]
hexColors[red]?[0] = ff
if (hexColors[gray]?[0] = ff) == nil {
println(It was not possible to change
color component)
}//Imprime:
//It was not possible to change color component
45. Encadeamento de opcionais
Optional chainging
— É possivel encadear multiplos níveis de opcionais
— se o tipo que você está tentando acessar não é
opcional, ele se tornará opcional através do
encadeamento
— se o tipo que você está tentando acessar já é
opcional, ele não se tornará mais opcional
46. Encadeamento de opcionais
let mary = Person()
if let street = mary.residence?.address?.street {
println(Mary lives in (street))
}
else {
println(I don't know the address)
}//imprime I don't know the address
//ok, não faz nada
mary.residence?.address?.street = Faria Lima
//erro de runtime
mary.residence!.address?.street = Faria Lima
47. Encadeamento de opcionais
métodos com retorno opcional
class Address {
//...
func moveTo(streetName: String, number: Int) {
self.street = streetName
self.number = number
}
}
48. Encadeamento de opcionais
métodos com retorno opcional
if let hasPrefix = mary.residence?
.address?
.street
.hasPrefix(Brigadeiro) {
println(Mary may live at Brigadeiro Faria Lima)
}
else {
println(I don't know the address)
}//imprime I don't know the address
49. Encadeamento de opcionais
métodos com retorno opcional
class Address {
//...
func moveTo(streetName: String?, number: Int?) - String? {
if streetName == nil || number == nil {
return nil
}
self.street = streetName
self.number = number
return (self.street), (self.number)
}
}
50. Encadeamento de opcionais
métodos com retorno opcional
if let newAddress = john.residence?
.address?.moveTo(nil, number: 123) {
println(Moved to (newAddress))
} //não imprime nada
if let newAddress = john.residence?
.address?.moveTo(Augusta, number: 123) {
println(Moved to (newAddress))
}
51. Encadeamento de opcionais
métodos com retorno opcional
if let hasPrefix = mary.residence?
.address?
.moveTo(Augusta, number: 123)? //note o ?
.hasPrefix(Brigadeiro) {
println(Mary may live at Brigadeiro Faria Lima)
}
52. Typecasting
Downcasting
Uma constante ou variável de um tipo pode referir
para uma instância ou variável de uma subclasse.
Se acredita que este pode ser o caso, você deve
fazer o downcast com o operador de type casting as.
53. Typecasting
Downcasting
Como pode falhar (caso sejam realmente de tipos
diferentes), vem em dois sabores
— Forma opcional de type casting as?
— Forma forçada de type casting as (sem o uso ?)
55. Typecasting
class Movie : MediaItem {
var director: String
init(name: String, director: String) {
self.director = director
super.init(name: name)
}
}
56. Typecasting
class Song : MediaItem {
var artist: String
init(name: String, artist: String) {
self.artist = artist
super.init(name: name)
}
}
57. Typecasting
let library = [
Movie(name:Iron Man, director: Jon Favreau),
Song(name: Hooked on a feeling: artist: Blue Swede)
]
58. Typecasting
let library = [
Movie(name:Iron Man, director: Jon Favreau),
Song(name: Hooked on a feeling: artist: Blue Swede)]
for item in library {
if let movie = item as? Movie {
println(Movie: (movie.name) directed by (movie.director))
}
else if let song = item as? Song {
println(Song: (song.name) by (song.artist))
}
}
59. Typecasting
var movieLibrary = [AnyObject]
movieLibrary.append(Movie(name:Iron Man,
director: Jon Favreau))
movieLibrary.append(Movie(name:2001: A Space Odyssey,
director: Stanley Kubrick))
60. Typecasting
var movieLibrary = [AnyObject]()
movieLibrary.append(Movie(name:Iron Man,
director: Jon Favreau))
movieLibrary.append(Movie(name:2001: A Space Odyssey,
director: Stanley Kubrick))
for item in movieLibrary {
let movie = item as Movie
println(Movie: (movie.name) directed by (movie.director))
}
61. Protocolos opcionais
Protocolos definem métodos, por exemplo, que devem
ser implementados por objetos que
Mas podemos declarar em um protocolo que a
implementação de um método é opcional.
Protocolo deve ser declarado com o atributo @objc
@objc só pode ser usado com structs e enuns
62. Protocolos opcionais
@objc protocol CounterDataSource {
func incrementForCount(count: Int) - Int ?
var fixedIncrement: Int { get } ?
}
63. Protocolos opcionais
@objc protocol CounterDataSource {
func incrementForCount(count: Int) - Int ?
var fixedIncrement: Int { get } ?
}
ERRADO
64. Protocolos opcionais
@objc protocol CounterDataSource {
optional func incrementForCount(count: Int) - Int
optional var fixedIncrement: Int { get }
}
65. Protocolos opcionais
@objc class Counter {
var count = 0
var dataSource: CounterDataSource?
func increment() {
if let amount = dataSource?.incrementForCount?(count) {
count += amount
}
else if let amount = dataSource?.fixedIncrement? {
count += amount
}
}
}
66. Navegando por águas mais profundas
Generics
struc StackT {
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() - T {
return items.removeLast()
}
}