Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

Dúvida na aula 6

Olá, Já programo em Android com Java há algum tempo e agora decidi me aventurar no swift e estou achando bem bacana embora o curso esteja com algumas coisinhas desatualizadas, valeria a pena uma revisada... Porém enquanto estava assistindo ao vídeo 4 da aula 6 ao tentar reproduzir o código que o Guilherme Silveira faz durante a aula não tive sucesso. Talvez por incompatibilidade das versões do Swift do curso com a que tenho aqui com o xcode.

O problema é que ao efetuar mudar as variáveis dos elementos da interface para que possam receber Optional e fazer uma validação simples, como no exemplo do vídeo eu continuo recebendo um Optional ao invés de receber uma String.

Como nesse trecho de código abaixo... Perceba que eu tenho o problema na variável hapiness pois preciso que ela seja um Integer e não uma String mas o método toInt() não existe mais. O próprio xcode então diz para eu utilizar o Int() no lugar do toInt()

@IBOutlet var nameField:UITextField?
@IBOutlet var hapinessField:UITextField?

 @IBAction func add() {
        if nameField == nil || hapinessField == nil {
            return
        }

        let name = nameField!.text
        let hapiness = Int(hapinessField!.text)

em relação a linha let hapiness = Int(hapinessField!.text) estou recebendo o seguinte erro:

Value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'?

Perceba que se eu forçar com ! eu consigo compilar sem problemas, porém gostaria de saber por qual motivo isso está ocorrendo pois sei que forçar a barra aqui não seria legal.

Seria algum problema do casting para integer? ou algo mudou nas versões do Swift? Como posso saber qual versão do swift estou utilizando aqui no momento? Utilizo o xcode 7.3.1 aqui.

Obrigado.

4 respostas
solução!

Quando você faz:

hapinessField!.text

isso retorna um String?(um Optional de String).

Como o Int() precisa receber uma String no seu inicializador e você está passando um String?, há um conflito de tipos, justificando o erro que você está tomando.

Logo, para extrair a String de dentro do seu Optional, é preciso fazer o seu unwrap. Para isso, usamos o ! após o text:

hapinessField!.text!

Com isso, seu código funciona:

let hapiness = Int(hapinessField!.text!)

Fala aí Bruno tudo bem?

O que está acontecendo é o seguinte o atributo text da classe UITextField é um String? (optional string).

E nesse caso o construtor da classe Int espera receber um valor do tipo String (e não um String?) . Por isso de ter que desembrulhar o optional com !. E ainda assim esse construtor retorna um Int? justamente porque pode falhar a conversão. E Nesse caso mais uma vez para pegar o valor você precisará desembrulhar ele com !.

Dessa forma:

let hapiness = Int(hapinessField!.text!)

Uma outra solução seria criar uma extension ou para a classe UITextField ou para a classe Int.

Se fosse na classe UITextField teriamos que retornar o valor do atributo text desembrulhado e/ou já convertido para Int (ou para qualquer outra classe)

extension UITextField{
    var stringValue: String { return text ?? ""} //dessa forma caso o atributo text seja nulo ele retorna uma string vazia caso contrário retorna o valor do atributo text
    var integerValue: Int { return Int(stringValue) ?? 0 } // aqui caso a conversão para Int retorne nulo ele retorna 0 caso contratio retorna o valor em inteiro (Int?)
}

Com esse extension eu posso simplesmente mudar minha declaração

de:

let hapiness = Int(hapinessField!.text)

para:

 let hapiness = hapinessField?.integerValue

Agora se fosse uma extension da classe Int temos que criar um novo construtor que receba um String? e devolva um o Int (e não um Int?)

    init?(_ text: String?){// o underline é para poder omitir o nome do parametro quando for usar esse construtor
        self.init(text!) //aqui desembrulho a string e passo para o construtor que já existe
    }
}

E dessa forma não mudaria nada na minha decalaração:

let hapiness = Int(hapinessField!.text)

Obviamente em ambas as soluções com extension temos que tomar um certo cuidado com o valor recebido e lidar com o Optional Int que eles retornam. Mas acho que deu para pegar a ideia.

A versão do Swift utilizada no XCode 7.3.1 é a 2.2 Sinceramente não sei onde visualizar essa informação dentro do XCode, mas tem essa informação na AppStore (vide link: https://itunes.apple.com/br/app/xcode/id497799835?mt=12)

Aqui tem um link da documentação da apple sobre extension: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Extensions.html

Espero ter ajudado, e se foi útil marque como solução =)

Poxa, obrigado! hehe, realmente, havia desconfiado de algo do tipo mas não sabia se era correto ou não forçar extrair o valor da variável dessa maneira.

De qualquer maneira obrigado :)

Fernando, muito obrigado também, sua resposta foi muito esclarecedora!!! Os fóruns da alura poderiam copiar aquele esquema de upvotes do stackoverflow não? haha