Swift에서 "포장 해제 된 값"은 무엇입니까?


155

이 튜토리얼 을 따라 iOS 8 / OSX 10.10 용 Swift를 배우고 있으며이 단락 ( Objects and Class 아래)에서와 같이 " unwrapped value " 라는 단어 가 여러 번 사용됩니다 .

선택적 값으로 작업 할 때?를 쓸 수 있습니다. 메서드, 속성 및 첨자 같은 작업 전에 만약 앞에 값이? nil, 이후의 모든 것? 무시되고 전체 표현식의 값은 nil입니다. 그렇지 않으면 선택적 값이 래핑되지 않고? 래핑되지 않은 값 에 작용 합니다 . 두 경우 모두 전체 표현식의 값은 선택적 값입니다.

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

나는 그것을 얻지 못하고 운없이 웹에서 검색했습니다.

이것은 무엇을 의미합니까?


편집하다

Cezary의 답변에서 원본 코드의 출력과 최종 솔루션 (놀이터에서 테스트)에는 약간의 차이가 있습니다.

원본 코드

원본 코드

세자리의 솔루션

세자리의 솔루션

수퍼 클래스의 속성은 두 번째 경우의 출력에 표시되고 첫 번째 경우에는 빈 개체가 있습니다.

두 경우 모두 결과가 동일하지 않습니까?

관련 Q & A : Swift의 선택적 값은 무엇입니까?


1
세자리의 대답은 바로 그 자리에 있습니다. 또한 iBooks
Daniel Storm

@DanielStormApps이 iBook은 내 질문에 링크 된 튜토리얼의 휴대용 버전입니다.)
Bigood

답변:


289

먼저 선택적 유형이 무엇인지 이해해야합니다. 선택적 유형은 기본적으로 변수 가 될 수 있음을 의미 합니다nil .

예:

var canBeNil : Int? = 4
canBeNil = nil

물음표는 사실 일 canBeNil수 있습니다 nil.

이것은 작동하지 않습니다 :

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

선택 사항 인 경우 변수에서 값을 가져 오려면 해제해야합니다 . 이것은 느낌표를 마지막에 두는 것을 의미합니다.

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

코드는 다음과 같아야합니다.

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

주석 :

물음표 대신 느낌표를 사용하여 자동으로 줄 바꿈 해제 옵션을 선언 할 수도 있습니다.

예:

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

따라서 코드를 수정하는 다른 방법은 다음과 같습니다.

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

편집하다:

당신이보고있는 차이점은 정확히 선택적 값이 포장 되어 있다는 사실의 증상입니다 . 그 위에 다른 레이어가 있습니다. 미개봉 는, 음, 미개봉 때문에 버전은 직선 객체를 보여줍니다.

빠른 놀이터 비교 :

운동장

첫 번째와 두 번째 경우에는 개체가 자동으로 래핑되지 않으므로 두 개의 "레이어"( {{...}})가 표시되고 세 번째 경우 {...}에는 개체가 자동으로 래핑 해제되기 때문에 하나의 계층 ( ) 만 표시됩니다 .

첫 번째 경우와 두 번째 두 경우의 차이점은로 설정된 경우 두 번째 두 경우에서 런타임 오류가 발생 optionalSquare한다는 것 nil입니다. 첫 번째 경우 구문을 사용하면 다음과 같이 할 수 있습니다.

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

1
명확한 설명에 감사드립니다! 내 질문에 포함 된 코드는 Apple의 튜토리얼 (질문의 링크)에서 인용되었으며, 그대로 작동해야한다고 생각합니다. 그러나 최종 솔루션과 원래 솔루션은 다른 결과를 출력합니다 (내 편집 참조). 어떤 생각?
Bigood

2
멋있는. 좋은 설명입니다. 그래도 여전히 혼란 스러워요. 왜 선택적 값을 사용하고 싶습니까? 언제 유용합니까? Apple은 왜이 동작과 구문을 만들었습니까?
Todd Lehman

1
클래스 속성과 관련하여 특히 관련이 있습니다. Swift init()는 클래스 의 함수 에서 모든 비 선택적 메소드를 초기화해야합니다 . Apple에서 발표 한 Swift 책에서 "기본 사항"(선택 사항 포함), "초기화"및 "선택적 체인"장을 읽는 것이 좋습니다.
Cezary Wojcik 2018 년

2
@ToddLehman Apple은 훨씬 안전한 코드 작성을 돕기 위해 이것을 만들었습니다. 예를 들어 누군가 null을 확인하는 것을 잊었 기 때문에 Java의 모든 null 포인터 예외가 프로그램을 중단한다고 상상해보십시오. 또는 nil을 확인하는 것을 잊었 기 때문에 Objective-C에서 이상한 동작이 발생합니다. 선택적 유형을 사용하면 nil을 처리하는 것을 잊을 수 없습니다. 컴파일러는이를 처리하도록 강제합니다.
Erik Engheim 2016 년

5
@AdamSmith — Java 배경에서 나오면 선택 사항의 사용을 확실히 볼 수 있지만 Objective-C 배경에서 (더 최근에) 오는 경우에도 여전히 사용하는 데 어려움이 있습니다. C에서는 명시 적으로 nil 객체에 메시지를 보낼 수 있습니다. 흠. 누군가가 코드를 사용하지 않는 동등한 코드보다 코드를 더 짧고 안전하게 만드는 방법을 보여주는 예제를 작성하고 싶습니다. 나는 그들이 유용하지 않다고 말하는 것이 아닙니다. 난 그냥 "얻지"말하고 있습니다.
Todd Lehman

17

기존의 정답은 훌륭하지만 이것을 완전히 이해하려면 매우 추상적이며 이상한 개념이기 때문에 좋은 비유가 필요하다는 것을 알았습니다.

따라서 정답 외에 다른 관점을 제시함으로써 "우뇌"(시각적 사고) 개발자를 도울 수 있도록하겠습니다. 여기에 많은 도움이 된 좋은 비유가 있습니다.

생일 선물 포장 비유

딱딱하고 딱딱한 색상의 포장으로 제공되는 생일 선물과 같은 옵션을 생각하십시오.

선물 포장을 풀 때까지 포장 안에 물건이 있는지 알 수 없습니다. 아마도 안에는 아무것도 없을 것입니다! 안에 무언가가 있다면, 그것은 또 다른 선물이 될 수 있으며, 이것은 또한 포장되어 있고 아무것도 포함하지 않을 수도 있습니다 . 당신은 마지막으로 줄 바꿈없다는 것을 발견하기 위해 100 개의 중첩 된 선물을 풀 수 있습니다 .

옵션의 값이 아닌 경우 nil, 이제 무언가를 포함하는 상자가 나타납니다 . 그러나 특히 값이 명시 적으로 입력되지 않고 변수이고 사전 정의 된 상수가 아닌 경우 , 상자 에 무엇이 있는지, 상자에 무엇이 있는지 또는 어떤 종류인지 에 대한 특정 정보를 알기 전에 상자열어야 할 수도 있습니다 . 실제 가치 입니다.

박스에 뭐가 들어 있어요?! 유추

변수를 풀더라도 SE7EN마지막 장면 ( 경고 : 스포일러 및 R 등급이 높은 파울 언어 및 폭력) 에서 여전히 Brad Pitt 와 같습니다. 이제 nil, 또는 무언가를 포함하는 상자가 있습니다 (그러나 무엇을 모릅니다).

당신은 무언가 의 유형을 알고있을 입니다. 예를 들어, 변수를 type으로 선언 한 경우 [Int:Any?]이전 유형의 랩핑 된 컨텐츠를 생성하는 정수 첨자가 포함 된 (잠재적으로 비어있는) 사전이 있음을 알 수 있습니다.

그렇기 때문에 Swift에서 컬렉션 유형 (사전 및 배열)을 처리하는 데 약간의 털이 발생할 수 있습니다.

지목 사항:

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)

nice 😊 😊😊 😊 😊😊 😊 😊😊
SamSol

비유를 사랑하십시오! 그렇다면 상자를 풀 수있는 더 좋은 방법이 있습니까? 코드 예제에서
David T.

Schrödinger의 고양이가 상자에 있습니다
Jacksonkr

나를 혼동 해 주셔서 감사합니다 ... 어쨌든 비어있는 생일 선물을주는 프로그래머는 무엇입니까? 좀 평균
delta2flat 0:02의

@Jacksonkr 또는 아닙니다.
amsmath

13

Swift는 유형 안전성을 높이 평가합니다. 전체 스위프트 언어는 안전을 염두에두고 설계되었습니다. Swift의 특징 중 하나이며 두 팔을 벌려 환영해야합니다. 깨끗하고 읽을 수있는 코드 개발을 지원하고 응용 프로그램 충돌을 방지합니다.

Swift의 모든 옵션은 ?기호 로 구분됩니다 . 을 설정함으로써 ?당신은 본질적으로 선택 당신이 선언되는 유형의 이름 뒤에 캐스팅 유형으로이되지되는 앞에있는 ?대신으로, 선택 유형입니다.


참고 : 변수 또는 유형 Int입니다 하지 같은 Int?. 그들은 서로 작동 할 수없는 두 가지 유형입니다.


옵션 사용

var myString: String?

myString = "foobar"

이 유형이 작업하고 있다는 의미 는 아닙니다String . 이는 String?(문자열 선택적 또는 선택적 문자열) 유형으로 작업하고 있음을 의미합니다 . 사실, 당신이 시도 할 때마다

print(myString)

런타임시 디버그 콘솔이 인쇄 Optional("foobar")됩니다. " Optional()"부분은이 변수가 런타임에 값을 갖거나 갖지 않을 수 있지만 현재 "foobar"문자열을 포함하고 있음을 나타냅니다. 이 " Optional()"표시는 선택적 값 "언 래핑"을 수행하지 않으면 유지됩니다.

랩핑 해제 당신이 지금이 아닌 선택 사항으로 유형을 캐스팅하는 것을 선택 수단을. 그러면 새 유형이 생성되고 해당 선택 사항에 상주하는 값이 새로운 비 선택적 유형에 지정됩니다. 이렇게하면 컴파일러가 확실한 값을 갖도록 보장 한대로 해당 변수에 대한 작업을 수행 할 수 있습니다.


조건부 래핑 해제 는 옵션의 값이 아닌지 확인합니다 nil. 이 아닌 경우 nil값이 할당되고 선택 사항이 아닌 상수로 래핑되지 않는 새로 작성된 상수 변수가 있습니다 . 그리고 거기에서 당신은 if블록 에서 비 옵션을 안전하게 사용할 수 있습니다 .

참고 : 랩핑 해제중인 선택적 변수와 동일한 이름을 조건부 래핑 해제 된 상수에 지정할 수 있습니다.

if let myString = myString {
    print(myString)
    // will print "foobar"
}

조건부 래핑 해제 옵션은 옵션 값에 액세스하는 가장 깨끗한 방법입니다. 옵션에 값이 0이면 if let 블록 내의 모든 항목이 실행되지 않기 때문입니다. 물론 if 문과 마찬가지로 else 블록을 포함시킬 수 있습니다

if let myString = myString {
    print(myString)
    // will print "foobar"
}
else {
    print("No value")
}

강제로 언 래핑!( "bang") 연산자 를 사용하여 수행됩니다 . 이것은 덜 안전하지만 여전히 코드를 컴파일 할 수 있습니다. 그러나 bang 연산자를 사용할 때마다 강제로 랩핑을 해제하기 전에 변수에 실제로 견고한 값이 포함되어 있는지 1000 % 확신해야합니다.

var myString: String?

myString = "foobar"

print(myString!)

위의 내용은 전적으로 유효한 Swift 코드입니다. myString"foobar"로 설정된 값을 출력합니다 . 사용자는 foobar콘솔에 인쇄 된 것으로 표시 됩니다. 그러나 값이 설정되지 않았다고 가정 해 봅시다.

var myString: String?

print(myString!) 

이제 우리는 다른 상황에 처해 있습니다. Objective-C와 달리 옵션을 강제로 풀려고 시도 할 때마다 옵션이 풀리지 않았고 옵션 nil을 풀려고 할 때 응용 프로그램 내부의 내용이 충돌하는 것을 확인합니다.


유형 캐스팅 포장 풀기 . 앞에서 말했듯이 unwrapping, 선택 사항이지만 실제로 선택 사항이 아닌 유형으로 캐스팅하고 있지만 선택 사항이 아닌 다른 유형으로 캐스팅 할 수도 있습니다. 예를 들면 다음과 같습니다.

var something: Any?

코드 어딘가에 변수 something가 값으로 설정됩니다. 어쩌면 우리는 제네릭을 사용하고 있거나 다른 논리가있을 수 있습니다. 따라서 나중에 우리 코드에서 사용하고 something싶지만 다른 유형이라면 여전히 다르게 취급 할 수 있습니다. 이 경우 as키워드를 사용하여 이를 판별 할 수 있습니다.

참고 : as연산자는 Swift에서 캐스트를 입력하는 방법입니다.

// Conditionally
if let thing = something as? Int {
    print(thing) // 0
}

// Optionally
let thing = something as? Int
print(thing) // Optional(0)

// Forcibly
let thing = something as! Int
print(thing) // 0, if no exception is raised

as키워드 의 차이점에 유의하십시오 . 이전에 옵션을 강제로 풀었을 때처럼 !bang 연산자를 사용했습니다 . 여기서는 동일한 작업을 수행하지만 선택 사항이 아닌 캐스팅 대신 캐스팅하는 것 Int입니다. 그리고 해야한다 으로 낙심 될 수 Int값이 때 강타 연산자를 사용하는 것과, 그렇지 않으면 nil응용 프로그램이 충돌합니다.

그리고 이러한 변수를 어떤 종류 또는 수학 연산에서 전혀 사용하려면 그렇게하기 위해 랩핑을 해제해야합니다.

예를 들어, Swift에서는 동일한 종류의 유효한 숫자 데이터 유형 만 서로 작동 할 수 있습니다. 당신이 가진 유형을 캐스팅 할 때 as!당신이 비록 당신이 그 변수의 내리 뜬을 강요 일부 가에 운영하고 응용 프로그램을 충돌하지하는 것이 안전하고, 해당 유형이다. 변수가 실제로 캐스팅 할 유형 인 한 괜찮습니다. 그렇지 않으면 손이 엉망이됩니다.

그럼에도 불구하고 캐스팅 as!하면 코드를 컴파일 할 수 있습니다. 로 캐스팅 as?하면 다른 이야기입니다. 사실, as?당신 Int을 완전히 다른 데이터 타입으로 선언합니다 .

지금이야 Optional(0)

그리고 숙제를하려고한다면

1 + Optional(1) = 2

당신의 수학 교사는 아마도 당신에게 "F"를 주었을 것입니다. 스위프트와 동일합니다. 스위프트를 제외하고는 등급을 부여하는 것보다는 컴파일하지 않을 것입니다. 하루가 끝나면 선택 사항은 실제로 nil 일 수 있습니다 .

안전 제일 아이들.


선택적 유형에 대한 좋은 설명. 나를 위해 물건을 정리하는 데 도움이되었습니다.
Tobe_Sta

0

'?' 선택적인 연쇄 표현을 ​​의미

합니다. '!'는 힘의 가치입니다.
여기에 이미지 설명을 입력하십시오

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.