Swift Programming Language 안내서 에는 다음 예제가 있습니다.
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { println("\(name) is being deinitialized") }
}
class Apartment {
let number: Int
init(number: Int) { self.number = number }
var tenant: Person?
deinit { println("Apartment #\(number) is being deinitialized") }
}
var john: Person?
var number73: Apartment?
john = Person(name: "John Appleseed")
number73 = Apartment(number: 73)
//From Apple's “The Swift Programming Language” guide (https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html)
그런 다음 아파트를 사람에게 할당 할 때 느낌표를 사용하여 “인스턴스 풀기”를 수행합니다.
john!.apartment = number73
“인스턴스 랩핑 해제”는 무엇을 의미합니까? 왜 필요한가요? 다음을 수행하는 것과 어떻게 다른가요?
john.apartment = number73
저는 스위프트 언어를 처음 접했습니다. 기본 사항을 낮추려고합니다.
업데이트 :
내가 놓친 퍼즐의 가장 큰 부분은 (답변에 직접 언급되지 않았지만 적어도이 글을 쓰는 시점에는 언급되지 않았습니다) 다음을 수행 할 때입니다.
var john: Person?
“내가 생각한대로” john
유형 Person
이고 무용지물 ” 이라는 의미는 아닙니다 . 나는 단순히 오해 한 Person
과 Person?
완전히 분리 된 유형입니다. 나는 다른 모든 것을, 파악되면 ?
, !
광기, 아래의 큰 응답, 더 많은 감각을했다.
답변
“인스턴스 랩핑 해제”는 무엇을 의미합니까? 왜 필요한가요?
내가 할 수있는 한 (이것은 나에게도 새롭다) …
“포장 된”이라는 용어 는 선택적 변수를 반짝 종이로 싸서 선물로 생각 해야 하며, 슬프게도 비어있을 수 있습니다 .
“래핑 된”경우, 선택적 변수의 값은 두 가지 가능한 값 (부울과 약간 비슷 함)이있는 열거 형입니다. 이 열거 형은 변수에 값이 있는지 ( Some(T)
) 또는 없는지 ( None
) 설명합니다.
값이 있으면 변수를 “래핑 해제”하여 ( T
from을 얻음 Some(T)
) 얻을 수 있습니다 .
john!.apartment = number73
와는 어떻게 다른john.apartment = number73
가요? (낙하산)
Optional 변수의 이름을 쓰는 경우 (예 : john
,없이 text !
), 값 자체 (T)가 아니라 “wrapped”열거 형 (일부 / 없음)을 나타냅니다. 따라서 john
의 인스턴스 Person
가 아니며 apartment
멤버 가 없습니다 .
john.apartment
// 'Person?' does not have a member named 'apartment'
실제 Person
값은 다양한 방법으로 래핑 해제 될 수 있습니다.
- “강제 풀기”:
john!
(Person
존재하는 경우 값을 제공하고 , 0이 아닌 경우 런타임 오류를 발생시킵니다) - “선택적 바인딩”:
if let p = john { println(p) }
(println
값이 존재 하는 경우 실행 ) - “선택적 체인”:
john?.learnAboutSwift()
(값이 존재하면이 구성 방법을 실행합니다)
나는 당신이 무사고에서 일어날 일과 그 가능성에 따라 포장 풀기 방법 중 하나를 선택했다고 생각합니다. 이 언어 디자인은 nil 케이스를 명시 적으로 처리하도록 강요합니다. Obj-C에 대한 안전성이 향상되었다고 가정합니다 (제로 케이스를 처리하는 것을 잊어 버릴 수있는 곳).
업데이트 :
느낌표는 “암시 적으로 래핑되지 않은 옵션”을 선언하는 구문에도 사용됩니다.
지금까지의 예에서 john
변수는로 선언되었으며 var john:Person?
선택 사항입니다. 해당 변수의 실제 값을 원하면 위의 세 가지 방법 중 하나를 사용하여 변수를 랩 해제해야합니다.
var john:Person!
대신 선언 된 경우 변수는 암시 적으로 래핑되지 않은 옵션입니다 (Apple의 책에서이 제목이있는 섹션 참조). 값에 액세스 할 때 이러한 종류의 변수를 랩 해제 할 필요가 없으며 john
추가 구문없이 사용할 수 있습니다. 그러나 애플의 책은 다음과 같이 말합니다.
변수가 나중에 nil이 될 가능성이있는 경우 암시 적으로 랩핑되지 않은 옵션을 사용해서는 안됩니다. 변수 수명 동안 nil 값을 확인해야하는 경우 항상 일반 선택적 유형을 사용하십시오.
업데이트 2 :
Mike Ash의 ” 흥미로운 스위프트 기능 ” 기사 는 선택적 유형에 대한 동기 부여를 제공합니다. 나는 그것이 훌륭하고 분명한 글이라고 생각합니다.
업데이트 3 :
느낌표 에 대한 암시 적으로 랩핑되지 않은 선택적 사용에 대한 또 다른 유용한 기사 : Chris Adamson 의 ” Swift and Last Mile “. 이 기사는 이것이 Objective-C 프레임 워크에서 사용되는 유형을 선언하는 데 사용되는 Apple의 실용적 조치라고 설명합니다. 유형을 선택 ( ?
) 또는 암시 적으로 래핑 () 으로 선언하는 !
것은 “안전과 편의 사이의 절충”입니다. 이 기사에 제공된 예제에서 Apple은 유형을 암시 적으로 랩핑하지 않은 것으로 선언하여 호출 코드를보다 편리하지만 덜 안전하게 만들었습니다.
아마도 애플은 장래에 프레임 워크를 뒤져서 암시 적으로 래핑되지 않은 ( “아마도 전혀 없음”) 매개 변수의 불확실성을 제거하고 옵션으로 대체 할 수도 있습니다 ( “특히, 문서화되어 있습니다!”) -Objective-C 코드의 정확한 동작을 기반으로 한 선택적 ( “아니오”) 선언입니다.
답변
차이점은 다음과 같습니다.
var john: Person?
요한이 무조건 될 수 있음을 의미
john?.apartment = number73
컴파일러는이 줄을 다음과 같이 해석합니다.
if john != nil {
john.apartment = number73
}
동안
john!.apartment = number73
컴파일러는이 줄을 간단히 다음과 같이 해석합니다.
john.apartment = number73
따라서! if 문을 풀어서 빠르게 실행하지만 john이 nil이면 런타임 오류가 발생합니다.
따라서 랩핑은 메모리 랩핑을 의미하는 것이 아니라 코드 랩핑을 의미합니다.이 경우 if 문으로 랩핑되며 Apple은 런타임 성능에주의를 기울이기 때문에 방법을 제공하려고합니다. 최고의 성능으로 앱을 실행하십시오.
최신 정보:
4 년 후이 답변으로 돌아가는 동안 Stackoverflow에서 가장 높은 명성을 얻었습니다. 이제 4 년이 지나서 여기서 언 래핑의 의미는 코드를 원래 컴팩트 한 형태에서 확장하는 것입니다. 또한 정의에 의해 확실하지 않기 때문에 그 객체 주위의 모호성을 제거하는 것을 의미합니다. 위의 애슐리의 대답과 마찬가지로 아무것도 포함 할 수없는 선물로 생각하십시오. 그러나 여전히 언 래핑은 코드 언 래핑이며 메모리 기반 언 래핑은 열거 형을 사용하는 것이 아니라고 생각합니다.
답변
TL; DR
Swift 언어에서 느낌표는 무엇을 의미합니까?
느낌표는 효과적으로 말합니다.“이 옵션은 분명히 가치가 있다는 것을 알고 있습니다. 사용하십시오.” 이것을 옵션 값의 강제 언 래핑이라고합니다.
예
let possibleString: String? = "An optional string."
print(possibleString!) // requires an exclamation mark to access its value
// prints "An optional string."
let assumedString: String! = "An implicitly unwrapped optional string."
print(assumedString) // no exclamation mark is needed to access its value
// prints "An implicitly unwrapped optional string."
답변
john이 선택적 var 인 경우 (따라 선언 됨)
var john: Person?
그러면 john이 값을 갖지 않을 수 있습니다 (Obj 값에서 nil 값)
느낌표는 기본적으로 컴파일러에 “이 값이 있다는 것을 알고 있으므로 테스트 할 필요가 없습니다”라고 알려줍니다. 사용하고 싶지 않다면 조건부로 테스트 할 수 있습니다.
if let otherPerson = john {
otherPerson.apartment = number73
}
이것의 내부는 john이 값을 가지고 있는지 평가할 것입니다.
답변
다른 유용하지만 더 세부적인 중심 답변에 추가 할 수있는 큰 그림 관점 :
Swift에서 느낌표는 여러 상황에서 나타납니다.
- 강제 랩핑 해제 :
let name = nameLabel!.text
- 암시 적으로 래핑되지 않은 옵션 :
var logo: UIImageView!
- 강제 주조 :
logo.image = thing as! UIImage
- 처리되지 않은 예외 :
try! NSJSONSerialization.JSONObjectWithData(data, [])
이 모든 것들은 다른 의미를 가진 다른 언어 구조이지만, 세 가지 중요한 공통점이 있습니다.
1. 느낌표는 Swift의 컴파일 타임 안전 점검을 우회합니다.
당신이 사용하는 경우 !
스위프트, 당신은 본질적으로 “이봐, 컴파일러, 난 당신이 오류가 생각하는지, 말을 할 수 여기에 발생하지만, 내가 아는 총 확실하게 그것이 않을 것입니다.”
유효한 모든 코드가 Swift의 컴파일 타임 유형 시스템의 상자 또는 언어의 정적 유형 검사에 적합 하지는 않습니다 . 오류가 발생하지 않는다는 것을 논리적으로 증명할 수있는 상황이 있지만 컴파일러에서 이를 증명할 수는 없습니다 . 그렇기 때문에 Swift의 디자이너는 이러한 기능을 처음에 추가했습니다.
그러나를 사용할 때마다 !
오류에 대한 복구 경로를 갖는 것을 배제합니다. 이는 다음을 의미합니다.
2. 느낌표는 잠재적 충돌입니다.
느낌표는 “스위프트 이봐, 나는 말한다 때문에 이 오류가 당신이하는 것이 더 나은 것을 결코 일어날 수있는 특정 내 모든 응용 프로그램을 충돌 그것의 복구 경로가 코드에 나를 위해보다.”
그것은 위험한 주장이다. 수 있습니다 당신은 당신의 코드의 불변에 대해 열심히 생각 중요한 코드에서, 그것은 그 가짜 출력이 충돌보다 더 나쁜 것입니다 수 있습니다 : 올바른합니다.
그러나 !
야생에서 볼 때 거의 그렇게 신경 쓰지 않습니다. 대신, 너무 자주 의미하는 것은 “이 값은 선택 사항이었고 왜 그것이 무의미한 지 또는 그 상황을 올바르게 처리하는 방법에 대해 너무 열심히 생각 하지는 않았지만 추가 !
하면 컴파일되었습니다 … 그래서 내 코드가 맞습니까?”
느낌표의 오만에주의하십시오. 대신에…
3. 느낌표는 드물게 사용하는 것이 가장 좋습니다.
이러한 !
구조는 ?
모두 오류 / 없음 사례를 처리하도록 하는 대응 요소를 가지고 있습니다.
- 조건부 풀기 :
if let name = nameLabel?.text { ... }
- 선택 사항 :
var logo: UIImageView?
- 조건부 캐스트 :
logo.image = thing as? UIImage
- 실패시 예외 :
try? NSJSONSerialization.JSONObjectWithData(data, [])
을 사용 !
하고 싶은 유혹이 있다면 , 왜 ?
대신 사용하지 않는지주의 깊게 고려하는 것이 좋습니다. !
작업이 실패하면 프로그램 충돌이 실제로 가장 좋은 방법 입니까? 왜 그 값이 선택 / 실패입니까?
무오류 / 오류 사례에서 코드가 취할 수있는 합리적인 복구 경로가 있습니까? 그렇다면 코딩하십시오.
그것이 불가능할 수 없다면, 오류가 발생할 수 없다면, 컴파일러가 그것을 알 수 있도록 논리를 재 작업하는 합리적인 방법이 있습니까? 그렇다면 그렇게하십시오. 코드 오류가 덜 발생합니다.
오류를 처리 할 합리적인 방법이없는 경우가 있으며 단순히 오류를 무시하여 잘못된 데이터로 진행하는 것이 충돌하는 것보다 나빠질 수 있습니다 . 그때 는 강제로 풀기를 사용하는 시대입니다.
정기적으로 전체 코드베이스를 검색하고 모든 코드베이스를 !
사용할 때마다 감사합니다. 조사를 위해 사용하는 사람은 거의 없습니다. (이 글을 쓰는 시점에서 전체 Siesta 프레임 워크에는 정확히 두 개의 인스턴스 가 있습니다.)
그것은 당신이해야 것은 아니다 결코 사용하지 !
당신이 그것을 사용해야 단지 – 코드에서 주의 깊게 , 그리고 기본 옵션 확인하지 않습니다.
답변
john
선택 사항 var
입니다. 따라서 nil
값을 포함 할 수 있습니다 . 값이 0이 아닌지 확인하려면 이름 !
끝에 a 를 사용하십시오 var
.
문서에서
“옵션에 값이 포함되어 있다고 확신하면 옵션 이름 끝에 느낌표 (!)를 추가하여 기본 값에 액세스 할 수 있습니다. 느낌표는 효과적으로 말합니다.“이 옵션은 분명히 가치가 있다는 것을 알고 있습니다. 사용하십시오.”
0이 아닌 값을 확인하는 또 다른 방법은
if let j = json {
// do something with j
}
답변
여기 몇 가지 예가 있어요.
var name:String = "Hello World"
var word:String?
word
선택적 값은 어디에 있습니까 ? 값을 포함하거나 포함하지 않을 수 있음을 의미합니다.
word = name
여기 name
에 값을 할당하여 할당 할 수 있습니다
var cow:String = nil
var dog:String!
dog
강제로 래핑되지 않은 곳 은 값을 포함해야 함을 의미합니다.
dog = cow
nil
래핑 해제에 할당 되어 있기 때문에 응용 프로그램이 중단됩니다