이 튜토리얼 을 따라 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의 선택적 값은 무엇입니까?
답변
먼저 선택적 유형이 무엇인지 이해해야합니다. 선택적 유형은 기본적으로 변수 가 될 수 있음을 의미 합니다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")
}
답변
기존의 정답은 훌륭하지만 이것을 완전히 이해하려면 매우 추상적이며 이상한 개념이기 때문에 좋은 비유가 필요하다는 것을 알았습니다.
따라서 정답 외에 다른 관점을 제시함으로써 “우뇌”(시각적 사고) 개발자를 도울 수 있도록하겠습니다. 여기에 많은 도움이 된 좋은 비유가 있습니다.
생일 선물 포장 비유
딱딱하고 딱딱한 색상의 포장으로 제공되는 생일 선물과 같은 옵션을 생각하십시오.
선물 포장을 풀 때까지 포장 안에 물건이 있는지 알 수 없습니다. 아마도 안에는 아무것도 없을 것입니다! 안에 무언가가 있다면, 그것은 또 다른 선물이 될 수 있으며, 이것은 또한 포장되어 있고 아무것도 포함하지 않을 수도 있습니다 . 당신은 마지막으로 줄 바꿈 이 없다는 것을 발견하기 위해 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)
답변
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 일 수 있습니다 .
안전 제일 아이들.