Swift!.opcionais.oh!.my()?!?

67
Swift! .opcionais? .oh! .my()?!?

description

Palestra sobre opcionais em Swift, ministrada na The Developers Conference

Transcript of Swift!.opcionais.oh!.my()?!?

Page 1: Swift!.opcionais.oh!.my()?!?

Swift!.opcionais?.oh!.my()?!?

Page 2: Swift!.opcionais.oh!.my()?!?

Tales Pinheiroco-founder Newt Labs,dev SalesForce na Top Information

@[email protected]

Page 3: Swift!.opcionais.oh!.my()?!?

DisclaimerLooking 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/

Page 4: Swift!.opcionais.oh!.my()?!?

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/

Page 5: Swift!.opcionais.oh!.my()?!?

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/

Page 6: Swift!.opcionais.oh!.my()?!?

A linguagem Zen

Opcionais - questão existêncial:

— Existe um valor, e é igual a x

ou

— NÃO existe um valor (nenhum MESMO!)

Page 7: Swift!.opcionais.oh!.my()?!?

nil versus Optional

— nil: "equivalente" em Objective-C, válido apenas para objetos

— Optional: valido para qualquer tipo

Page 8: Swift!.opcionais.oh!.my()?!?

nil versus Optional

— nil: "equivalente" em Objective-C, válido apenas para objetos

— Optional: valido para qualquer tipo

Page 9: Swift!.opcionais.oh!.my()?!?

Quando usar ?

let possibleNumber = "123"let convertedNumber = possibleNumber.toInt()

let anotherPossibleNumber = "Hello, World"let whatIsMyValue = anotherPossibleNumber.toInt()

Page 10: Swift!.opcionais.oh!.my()?!?

Qual o tipo ?

let possibleNumber = "123"let convertedNumber = possibleNumber.toInt()

let anotherPossibleNumber = "Hello, World"let whatIsMyValue = anotherPossibleNumber.toInt()

//possibleNumber = 123, whatIsMyValue=nil

Page 11: Swift!.opcionais.oh!.my()?!?

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?

Page 12: Swift!.opcionais.oh!.my()?!?

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?

Page 13: Swift!.opcionais.oh!.my()?!?

Definição manual do tipo

var myVar: String?//compilador atribui automaticamente o valor nil

Page 14: Swift!.opcionais.oh!.my()?!?

Declarações if e desempacotamento forçadoforced 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.

Page 15: Swift!.opcionais.oh!.my()?!?

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"

Page 16: Swift!.opcionais.oh!.my()?!?

Desenpacotamento implicito de opcionaisImplictly 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.”

Page 17: Swift!.opcionais.oh!.my()?!?

Desenpacotamento implicito de opcionaisImplictly 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()

Page 18: Swift!.opcionais.oh!.my()?!?

Desenpacotamento implicito de opcionaisImplictly 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}

Page 19: Swift!.opcionais.oh!.my()?!?

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")}

Page 20: Swift!.opcionais.oh!.my()?!?

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")}

Page 21: Swift!.opcionais.oh!.my()?!?

nil coalescing operator

Considere o código:

var a : Int? //implicitamente atribuido valor nilvar b = 0var 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

Page 22: Swift!.opcionais.oh!.my()?!?

nil coalescing operator

levemente analogo, em Objective-C (na verdade, C99), a:

c = a ?: b

Page 23: Swift!.opcionais.oh!.my()?!?

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"

Page 24: Swift!.opcionais.oh!.my()?!?

Opcionais e subscripts (dicionários)

var hexColors = ["red" : "ff0000", "green" : "00ff00", "blue" : "0000ff"]var hexForRed = hexColors["red"]

Page 25: Swift!.opcionais.oh!.my()?!?

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?"

Page 26: Swift!.opcionais.oh!.my()?!?

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...

Page 27: Swift!.opcionais.oh!.my()?!?

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

Page 28: Swift!.opcionais.oh!.my()?!?

Tuplas opcionais

Podemos ter tuplas com valores opcionais ou tuplas opcionais:

(Int, Int?)

versus

(Int, Int)?

Page 29: Swift!.opcionais.oh!.my()?!?

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

Page 30: Swift!.opcionais.oh!.my()?!?

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)}

Page 31: Swift!.opcionais.oh!.my()?!?

Enumerações - Raw value

enum WeekDay: Int { case Sunday = 0, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday}

let weekDayNumber = WeekDay.Friday.toRaw() //weekDay = 6

Page 32: Swift!.opcionais.oh!.my()?!?

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

Page 33: Swift!.opcionais.oh!.my()?!?

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

Page 34: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaisOptional 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

Page 35: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaisOptional 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

Page 36: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaisOptional chainging

class Residence { var numberOfRooms = 1}

class Person { var residence: Residence?}

Page 37: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaisOptional chainging

let john = Person()

let numberOfRooms = john.residence!.numberOfRooms// PAN! -> erro de runtime

//mas o código abaixo não tem problemaif let numberOfRooms = john.residence?.numberOfRooms { println("John's residence has \ \(numberOfRooms) room(s).")}

Page 38: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaisOptional 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?"

Page 39: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaisOptional chainging

class Room { var name: String init(name: String) { self.name = name }}

class Address { var street: String? var number: Int?}

Page 40: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaisOptional 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?}

Page 41: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaisOptional chainging

let john = Person()let residence = Residence()residence.address = someAddressresidence.rooms.append(Room(name: "Kitchem"))john.residence = residenceprintln("John's residence has \ \(john.residence?.numberOfRooms) room(s)")//Imprime: "John's residence has Optional(1) room(s)"

Page 42: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaisOptional 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")"

Page 43: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaisOptional chainging

var hexColors = ["red" : ["00", "00", "00"], "green" : ["00", "ff", "00"], "blue" : ["00", "00", "ff"]]hexColors["red"]?[0] = "ff"

Page 44: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaisOptional 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"

Page 45: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaisOptional 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

Page 46: Swift!.opcionais.oh!.my()?!?

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 nadamary.residence?.address?.street = "Faria Lima"//erro de runtimemary.residence!.address?.street = "Faria Lima"

Page 47: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaismétodos com retorno opcional

class Address { //... func moveTo(streetName: String, number: Int) { self.street = streetName self.number = number }}

Page 48: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaismé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"

Page 49: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaismé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)" }}

Page 50: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaismé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)")}

Page 51: Swift!.opcionais.oh!.my()?!?

Encadeamento de opcionaismé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")}

Page 52: Swift!.opcionais.oh!.my()?!?

TypecastingDowncasting

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.

Page 53: Swift!.opcionais.oh!.my()?!?

TypecastingDowncasting

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 ?)

Page 54: Swift!.opcionais.oh!.my()?!?

Typecasting

class MediaItem { var name: String init(name: String) { self.name = name }}

Page 55: Swift!.opcionais.oh!.my()?!?

Typecasting

class Movie : MediaItem { var director: String init(name: String, director: String) { self.director = director super.init(name: name) }}

Page 56: Swift!.opcionais.oh!.my()?!?

Typecasting

class Song : MediaItem { var artist: String init(name: String, artist: String) { self.artist = artist super.init(name: name) }}

Page 57: Swift!.opcionais.oh!.my()?!?

Typecasting

let library = [ Movie(name:"Iron Man", director: "Jon Favreau"), Song(name: "Hooked on a feeling": artist: "Blue Swede")]

Page 58: Swift!.opcionais.oh!.my()?!?

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)") }}

Page 59: Swift!.opcionais.oh!.my()?!?

Typecasting

var movieLibrary = [AnyObject]movieLibrary.append(Movie(name:"Iron Man", director: "Jon Favreau"))movieLibrary.append(Movie(name:"2001: A Space Odyssey", director: "Stanley Kubrick"))

Page 60: Swift!.opcionais.oh!.my()?!?

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)")}

Page 61: Swift!.opcionais.oh!.my()?!?

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

Page 62: Swift!.opcionais.oh!.my()?!?

Protocolos opcionais

@objc protocol CounterDataSource { func incrementForCount(count: Int) -> Int ? var fixedIncrement: Int { get } ?}

Page 63: Swift!.opcionais.oh!.my()?!?

Protocolos opcionais

@objc protocol CounterDataSource { func incrementForCount(count: Int) -> Int ? var fixedIncrement: Int { get } ?}

ERRADO

Page 64: Swift!.opcionais.oh!.my()?!?

Protocolos opcionais

@objc protocol CounterDataSource { optional func incrementForCount(count: Int) -> Int optional var fixedIncrement: Int { get }}

Page 65: Swift!.opcionais.oh!.my()?!?

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 } }}

Page 66: Swift!.opcionais.oh!.my()?!?

Navegando por águas mais profundasGenerics

struc Stack<T> { var items = [T]() mutating func push(item: T) { items.append(item) }

mutating func pop() -> T { return items.removeLast() }}

Page 67: Swift!.opcionais.oh!.my()?!?

Generics

extension Stack { var topItem: T? { return items.isEmpty ? nil : items[items.count - 1] }}