ios - O que é um “valor desembrulhado” no Swift?




ios8 (3)

'? significa expressão de encadeamento opcional

o '!' significa valor de força

Estou aprendendo o Swift para iOS 8 / OSX 10.10 seguindo este tutorial , e o termo " valor desembrulhado " é usado várias vezes, como neste parágrafo (em Objetos e Classe ):

Ao trabalhar com valores opcionais, você pode escrever? antes de operações como métodos, propriedades e subscrição. Se o valor antes do? é nulo, tudo depois do? é ignorado e o valor da expressão inteira é nulo. Caso contrário, o valor opcional é desembrulhado e tudo após o? age sobre o valor desembrulhado . Em ambos os casos, o valor da expressão inteira é um valor opcional.

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare?.sideLength

Eu não entendo, e procurei na web sem sorte.

O que isso significa?

Editar

Da resposta de Cezary, há uma pequena diferença entre a saída do código original e a solução final (testada no playground):

Código original

A solução de Cezary

As propriedades da superclasse são mostradas na saída no segundo caso, enquanto há um objeto vazio no primeiro caso.

O resultado não é o mesmo em ambos os casos?

Perguntas e Respostas Relacionadas: O que é um valor opcional no Swift?


A resposta correta existente é ótima, mas descobri que para mim entender isso completamente, eu precisava de uma boa analogia, já que esse é um conceito muito abstrato e esquisito.

Então, deixe-me ajudar os colegas "de cérebro direito" (pensamento visual), dando uma perspectiva diferente, além da resposta correta. Aqui está uma boa analogia que me ajudou muito.

Analogia do envolvimento do presente de aniversário

Pense nos opcionais como sendo como presentes de aniversário que vêm em embalagens duras, duras e coloridas.

Você não sabe se há algo dentro da embalagem até você desembrulhar o presente - talvez não haja nada dentro! Se há algo dentro, pode ser ainda outro presente, que também é envolvido, e que também pode conter nada . Você pode até mesmo desembrulhar 100 presentes aninhados para finalmente descobrir que não havia nada além de embrulhar .

Se o valor do opcional não for nil , agora você revelou uma caixa contendo algo . Mas, especialmente se o valor não for explicitamente digitado e for uma variável e não uma constante predefinida, talvez você ainda precise abrir a caixa antes de saber algo específico sobre o que está na caixa, como o tipo ou qual é a valor real é.

O que está na caixa?! Analogia

Mesmo depois de você desembrulhar a variável, você ainda é como Brad Pitt na última cena em SE7EN ( aviso : spoilers e muito linguagem censurada e violência), porque mesmo depois de você ter desembrulhado o presente, você está na seguinte situação: você agora tem nil , ou uma caixa contendo alguma coisa (mas você não sabe o quê).

Você pode saber o tipo de algo . Por exemplo, se você declarasse a variável como sendo tipo, [Int:Any?] , Saberia que tinha um Dicionário (potencialmente vazio) com índices inteiros que rendem conteúdo embrulhado de qualquer tipo antigo.

É por isso que lidar com tipos de coleção (Dicionários e Matrizes) em Swift pode ser meio cabeludo.

Caso em questão:

typealias presentType = [Int:Any?]

func wrap(i:Int, gift:Any?) -> presentType? {
    if(i != 0) {
        let box : presentType = [i:wrap(i-1,gift:gift)]
        return box
    }
    else {
        let box = [i:gift]
        return box
    }
}

func getGift() -> String? {
    return "foobar"
}

let f00 = wrap(10,gift:getGift())

//Now we have to unwrap f00, unwrap its entry, then force cast it into the type we hope it is, and then repeat this in nested fashion until we get to the final value.

var b4r = (((((((((((f00![10]! as! [Int:Any?])[9]! as! [Int:Any?])[8]! as! [Int:Any?])[7]! as! [Int:Any?])[6]! as! [Int:Any?])[5]! as! [Int:Any?])[4]! as! [Int:Any?])[3]! as! [Int:Any?])[2]! as! [Int:Any?])[1]! as! [Int:Any?])[0])

//Now we have to DOUBLE UNWRAP the final value (because, remember, getGift returns an optional) AND force cast it to the type we hope it is

let asdf : String = b4r!! as! String

print(asdf)

Primeiro, você precisa entender o que é um tipo opcional. Um tipo opcional significa basicamente que a variável pode ser nil .

Exemplo:

var canBeNil : Int? = 4
canBeNil = nil

O ponto de interrogação indica o fato de que canBeNil pode ser nil .

Isso não funcionaria:

var cantBeNil : Int = 4
cantBeNil = nil // can't do this

Para obter o valor da sua variável, se for opcional, você terá que descompactá-lo . Isso significa apenas colocar um ponto de exclamação no final.

var canBeNil : Int? = 4
println(canBeNil!)

Seu código deve ficar assim:

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare!.sideLength

Um sidenote:

Você também pode declarar que os opcionais serão desfeitas automaticamente usando um ponto de exclamação em vez de um ponto de interrogação.

Exemplo:

var canBeNil : Int! = 4
print(canBeNil) // no unwrapping needed

Portanto, uma maneira alternativa de corrigir seu código é:

let optionalSquare: Square! = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare.sideLength

EDITAR:

A diferença que você está vendo é exatamente o sintoma do fato de que o valor opcional é empacotado . Há outra camada em cima dela. A versão desembrulhada mostra apenas o objeto reto, porque está, bem, sem invólucro.

Uma comparação rápida de recreio:

No primeiro e segundo casos, o objeto não está sendo automaticamente desembrulhado, então você vê duas "camadas" ( {{...}} ), enquanto no terceiro caso, você vê apenas uma camada ( {...} ) porque o objeto está sendo automaticamente desembrulhado.

A diferença entre o primeiro caso e o segundo dois casos é que os dois segundos casos lhe darão um erro de tempo de execução se o optionalSquare estiver definido como nil . Usando a sintaxe no primeiro caso, você pode fazer algo assim:

if let sideLength = optionalSquare?.sideLength {
    println("sideLength is not nil")
} else {
    println("sidelength is nil")
}




ios8