Swift 언어에서 느낌표는 무엇을 의미합니까?


518

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이고 무용지물 " 이라는 의미는 아닙니다 . 나는 단순히 오해 한 PersonPerson?완전히 분리 된 유형입니다. 나는 다른 모든 것을, 파악되면 ?, !광기, 아래의 큰 응답, 더 많은 감각을했다.

답변:


530

"인스턴스 랩핑 해제"는 무엇을 의미합니까? 왜 필요한가요?

내가 할 수있는 한 (이것은 나에게도 새롭다) ...

"포장 된"이라는 용어 는 선택적 변수를 반짝 종이로 싸서 선물로 생각 해야 하며, 슬프게도 비어있을 수 있습니다 .

"래핑 된"경우, 선택적 변수의 값은 두 가지 가능한 값 (부울과 약간 비슷 함)이있는 열거 형입니다. 이 열거 형은 변수에 값이 있는지 ( Some(T)) 또는 없는지 ( None) 설명합니다.

값이 있으면 변수를 "래핑 해제"하여 ( Tfrom을 얻음 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 코드의 정확한 동작을 기반으로 한 선택적 ( "아니오") 선언입니다.


이 설명에 대해 잘 모르겠습니다. !없이 코드를 실행하면! 여전히 실제 값을 반환합니다. 아마! 속도입니다?
Richard Washington

확인. 그래서 문서는 사용에 대해 이야기합니다! 당신은 확실히 포장을 풀 수 있습니다 알 때. 그러나 코드를 사용하지 않고 (목록에 대한 네 번째 옵션-암시 적 언 래핑) 먼저 확인하지 않고 코드를 잘 실행할 수 있습니다. 값을 다시 얻거나 nil이면 nil을 얻습니다. 그러나 당신이 그것이 아니라는 것을 확실히 알고 있다면 사용하십시오 ......... 그러나 나는 왜 당신이 이것을하는지 알 수 없습니까?
Richard Washington

2
안녕하세요 @RichardWashington-이 답변 중 일부를 명확하게 설명하는 업데이트를 추가했습니다.
Ashley

업데이트 3은 내가 찾고있는 것입니다. 그것을 읽기 전에 애플이 NSURLCredential과 같은 것을 반환했을 때 거짓말하고 있다고 생각했습니다! 실제로는 없을 수 있습니다.
Golden Thumb

@Ashley 환상적인 답변에 감사드립니다. 이 답변과 Apple의 빠른 코드 예제를 읽은 후에는 안전과 생산성 간의 상충 관계에서 일반적으로 더 안전한 편이 가장 좋습니다. 내가 찾은 주목할만한 예외는 Apple이 UI 요소에 강제 언 래핑을 사용하는 경우입니다. 첫 번째로 스토리 보드를 포함 할 때 UI 요소는 일반적으로 선택 사항이므로 (프로그램 적으로 값이 할당되지 않기 때문에) 두 번째는 거의 있기 때문입니다. 포함하는 뷰 컨트롤러가 nil이 아닌 한 절대 nil이 아닙니다.
Mihir

127

차이점은 다음과 같습니다.

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 년이 지나서 여기서 언 래핑의 의미는 코드를 원래 컴팩트 한 형태에서 확장하는 것입니다. 또한 정의에 의해 확실하지 않기 때문에 그 객체 주위의 모호성을 제거하는 것을 의미합니다. 위의 애슐리의 대답과 마찬가지로 아무것도 포함 할 수없는 선물로 생각하십시오. 그러나 여전히 언 래핑은 코드 언 래핑이며 메모리 기반 언 래핑은 열거 형을 사용하는 것이 아니라고 생각합니다.


9
내 놀이터에서 john.apartment = number73이 컴파일되지 않으면 john? .apartment = number73
Chuck Pinkert를

2
@ChuckPinkert가 맞습니다 .4 번째 줄을 john?로 편집해야합니까? .apartment = number73, 멋진 답변!
Bruce

john.apartment = number73은 오류 : 선택적 유형 'Person?'의 값 래핑되지 않음 : '!' 또는 '?'?
스파이더 맨

4
언 래핑은 wrt 성능과 관련이 없습니다. "nil check"는 여전히 런타임에 수행되어야합니다. 유일한 차이점은 Optional에 값이 없을 경우 런타임 오류가 발생한다는 것입니다.
madidier 2016 년

67

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."

출처 : https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_399


11
지금 무슨 일 이 일어나고 있는지 이해하기 때문에 당신의 대답은 위대 합니다. 내가 이해하지 못하는 것은 암묵적으로 래핑되지 않은 옵션이 존재하는 이유입니다. 일반 문자열 유형이 아닌 암시 적으로 랩핑되지 않은 선택적 문자열로 정의 된 것을 작성하는 이유는 무엇입니까? 그 후의 사용법은 동일합니다. 내가 무엇을 놓치고 있습니까?
pachun

이것은 더 이상 사실이 아닌 것 같습니다. Swift 5 repl에서 내가 let f: String! = "hello"한 다음 print(f)출력 Optional("hello")하면 그냥 출력 되지 않습니다 "hello".
numbermaniac

37

john이 선택적 var 인 경우 (따라 선언 됨)

var john: Person?

그러면 john이 값을 갖지 않을 수 있습니다 (Obj 값에서 nil 값)

느낌표는 기본적으로 컴파일러에 "이 값이 있다는 것을 알고 있으므로 테스트 할 필요가 없습니다"라고 알려줍니다. 사용하고 싶지 않다면 조건부로 테스트 할 수 있습니다.

if let otherPerson = john {
    otherPerson.apartment = number73
}

이것의 내부는 john이 값을 가지고 있는지 평가할 것입니다.


4
답장을 보내 주셔서 감사합니다. 이제 느낌표가 무엇인지 이해 하고 있습니다. 아직도 머리를 감쌀 까요 ? ... 컴파일러에게 "이 값이 있다는 것을 알고 있습니다. 그것". 컴파일러가 테스트하지 않으면 무엇을 사나요? 느낌표가 없으면 컴파일러에서 오류가 발생합니까 (아직 환경이 없지만 Swift를 테스트 할 수있는 위치)? 입니다! 모든 옵션 변수에 100 %가 필요합니까? 그렇다면 왜 애플이 그것의 부족 을 만드는 것과 반대로, 그것으로 귀찮게 했습니까 ! "이것은 가치가 있다는 것을 알고 있습니다. 테스트 할 필요가 없습니다"?
Troy

"컴파일러에서 오류가 발생합니까?"-예상대로 값을 반환해도 여전히 작동하지 않습니다. 나는 이것을 얻지 못한다. 입니다! 확실 할 때 속도 만?
Richard Washington

실제로 나중에 문서에서 아래 예제를 사용하여 암시 적으로 래핑되지 않은 옵션에 대해 이야기합니다. “let possibleString: String? = "An optional string." println(possibleString!) // requires an exclamation mark to access its value // prints "An optional string.” 하지만 no! 뭔가 이상한 것 같습니다.
Richard Washington

3
@RichardWashington 당신은 좋은 이유 때문에 혼란스러워합니다! 문서의 예제는 일부 내용을 제외하고 있으며 println을 사용하기 때문에 오해의 소지가 있습니다. 분명히, 선택 사항의 언 래핑이 필요하지 않은 최소한 두 개의 인스턴스가 있습니다. 하나는 println을 사용할 때입니다. 다른 하나는 문자열 보간을 사용할 때입니다. 그렇다면 println과 문자열 보간이 덮개 아래에서 풀릴 수 있습니까? 누군가가 이것에 대해 더 많은 통찰력을 가지고있을 수도 있습니다. Xcode6 Beta 헤더 정의를 살펴보면이 마법에 대해 아무것도 알 수 없었습니다.
mbeaty

예, 나는 그것을 얻을 John?하고 John서로 다른 두 가지 종류가 있습니다. 하나는 선택 사항 유형이고 다른 하나는 유형 유형입니다. Person을 꺼내려면 옵션 Person을 풀어야합니다. 그러나 당신이 말했듯이, 실제로는 실제로 아무것도하지 않고도 이러한 상황에서 발생하는 것으로 보입니다. 이것은 ~을 만드는 것 같습니다! 불필요한. 그렇지 않으면! 항상 선택 사항이지만 컴파일 시간 오류를 잡기 위해 권장되는 방법입니다. vars / let을 특정 유형에 할당하는 것과 같은 종류는 명시 let John: Person = ...적이지만 유추 할 수도 있습니다 let John = ....
Richard Washington

27

다른 유용하지만 더 세부적인 중심 답변에 추가 할 수있는 큰 그림 관점 :

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 프레임 워크에는 정확히 두 개의 인스턴스 가 있습니다.)

그것은 당신이해야 것은 아니다 결코 사용하지 !당신이 그것을 사용해야 단지 - 코드에서 주의 깊게 , 그리고 기본 옵션 확인하지 않습니다.


func isSubscriptionActive(receiptData: NSDictionary?) -> Bool { if(receiptData == nil) { return false; } return (hasValidTrial(receiptData!) || isNotExpired(receiptData!)) && isNotCancelled(receiptData!) } 주어진 3 더 나은 방법이 있습니까?
jenson-button-event

당신은 말할 수있다func isSubscriptionActive(receiptData: NSDictionary?) -> Bool { guard let nonNilReceiptData = receiptData else { return false} return (hasValidTrial(nonNilReceiptData) || isNotExpired(nonNilReceiptData)) && isNotCancelled(nonNilReceiptData) }
rkgibson2

느낌표는 안전 점검을 우회하지 않습니다. 옵션이 nil이면 충돌 이 보장 됩니다. 옵션은 항상 확인됩니다. 안전 점검을하는 것은 매우 잔인한 방법입니다.
gnasher729

@ gnasher729 답변에서 알 수 있듯이 안전한 런타임 오류 를 위해 컴파일 타임 안전 검사를 우회합니다 .
Paul Cantrell

24

john선택 사항 var입니다. 따라서 nil값을 포함 할 수 있습니다 . 값이 0이 아닌지 확인하려면 이름 !끝에 a 를 사용하십시오 var.

문서에서

“옵션에 값이 포함되어 있다고 확신하면 옵션 이름 끝에 느낌표 (!)를 추가하여 기본 값에 액세스 할 수 있습니다. 느낌표는 효과적으로 말합니다.“이 옵션은 분명히 가치가 있다는 것을 알고 있습니다. 사용하십시오.”

0이 아닌 값을 확인하는 또 다른 방법은

    if let j = json {
        // do something with j
    }

1
그렇습니다. 나는 문서에서 이것을 보았지만 여전히 불필요 해 보입니다. 저 john.apartment = number73에게도 "이 옵션은 반드시 가치가 있다는 것을 알고 있습니다. 사용하십시오."
Troy

6
예, 그러나 요점은 기본적으로 Swift가 컴파일 타임에 오류를 잡으려고한다는 것입니다. 이 변수에 nil을 포함 할 수 없다는 것을 알고 있거나 생각하는 경우 느낌표를 사용하여 해당 검사를 제거 할 수 있습니다.
lassej 2016 년

16

여기 몇 가지 예가 있어요.

var name:String = "Hello World"
var word:String?

word선택적 값은 어디에 있습니까 ? 값을 포함하거나 포함하지 않을 수 있음을 의미합니다.

word = name 

여기 name에 값을 할당하여 할당 할 수 있습니다

var cow:String = nil
var dog:String!

dog강제로 래핑되지 않은 곳 은 값을 포함해야 함을 의미합니다.

dog = cow

nil래핑 해제에 할당 되어 있기 때문에 응용 프로그램이 중단됩니다


1
var c:Int = nil"지정된 유형 'int'를 초기화 할 수 없음"
Asususer

15

이 경우 ...

var John : 사람!

즉, John이 처음에는 nil 값을 가지며, 설정되고 한 번 설정된 후에는 다시 nil-led되지 않습니다. 따라서 편의상 "암시 적으로 래핑되지 않은 선택적"이므로 선택적 var에 액세스하기 위해 더 쉬운 구문을 사용할 수 있습니다.


1
감사합니다. 또한 이것을 설명하는 다음 링크를 찾았습니다. 이런 종류의 유형을 "암시 적으로 래핑되지 않은 옵션"이라고합니다. stackoverflow.com/questions/24122601/…
Kaydell

5

C 계열 언어를 사용하는 경우 "메모리 주소 0 (NULL) 일 수있는 X 유형의 객체에 대한 포인터"를 생각하고 동적으로 입력 된 언어를 사용하는 경우 "X 형이지만 정의되지 않은 유형일 수있는 객체"라고 생각합니다. 로터리 방식으로 첫 번째 방법은 비슷하지만 실제로 올바른 것은 아닙니다.

당신이 생각 해야하는 방식은 마치 다음과 같은 객체입니다.

struct Optional<T> {
   var isNil:Boolean
   var realObject:T
}

선택적 값을 테스트 할 때 foo == nil실제로 반환하고 foo.isNil, 말할 때 assertion과 함께 foo!반환 한다고 말합니다 . 이 작업을 수행 할 때 실제로 nil이면 런타임 오류이므로 값이 nil이 아니라고 확신하지 않는 한 일반적으로 대신 조건부 let을 사용하려고하기 때문에이 점에 유의 해야합니다. 이런 종류의 속임수는 값이 어디에나 없는지 테스트하지 않아도 언어를 강력하게 입력 할 수 있음을 의미합니다.foo.realObjectfoo.isNil == falsefoofoo!

실제로는 컴파일러가 작업을 수행하기 때문에 실제로 그렇게 동작하지는 않습니다. 상위 레벨 에는와 Foo?분리 된 유형 이 있으며 Foo, 이는 유형을 허용하는 펑크 Foo가 nil 값을 수신 하지 못하게 하지만, 하위 레벨에서는 선택적 값이 특성이나 메소드가 없기 때문에 실제 오브젝트가 아닙니다. 실제로 강제 랩핑 해제시 적절한 테스트를 통해 NULL (0)에 의해 포인터 일 수 있습니다.

다음과 같이 느낌표가 표시되는 다른 상황이 있습니다.

func foo(bar: String!) {
    print(bar)
}

이는 강제 랩핑 해제 옵션 (선택 사항)을 수락하는 것과 거의 같습니다.

func foo(bar: String?) {
    print(bar!)
}

이를 사용하여 기술적으로 선택적 값을 허용하지만 값이 0이 아닌 경우 런타임 오류가 발생하는 방법을 사용할 수 있습니다. Swift의 현재 버전에서 이것은 분명히 nil이 아닌 어설 션을 우회하므로 대신 낮은 수준의 오류가 발생합니다. 일반적으로 좋은 생각은 아니지만 다른 언어에서 코드를 변환 할 때 유용 할 수 있습니다.



3

C #에 익숙한 경우 물음표를 사용하여 선언되는 Nullable 형식과 같습니다.

Person? thisPerson;

이 경우 느낌표는 다음과 같이 nullable 형식의 .Value 속성에 액세스하는 것과 같습니다.

thisPerson.Value

2

값이없는 객관적인 C 변수는 'nil'과 같았습니다 ( 'nil'값을 0과 false로 사용할 수도 있음). 따라서 조건문에 변수를 사용할 수있었습니다 (값을 갖는 변수는 'TRUE와 동일합니다' '및 값이없는 값은'FALSE '와 같음).

Swift는 '선택적 값'을 제공하여 형식 안전성을 제공합니다. 즉, 다른 유형의 변수를 할당하여 생성 된 오류를 방지합니다.

따라서 Swift에서는 조건문에 부울 만 제공 할 수 있습니다.

var hw = "Hello World"

여기서조차도 'hw'는 문자열이지만 목표 C와 같은 if 문에서는 사용할 수 없습니다.

//This is an error

if hw

 {..}

이를 위해 다음과 같이 생성해야합니다.

var nhw : String? = "Hello World"

//This is correct

if nhw

 {..}

2

! 객체의 끝에서 객체는 선택적이며 그렇지 않으면 nil을 반환 할 수 있으면 줄 바꿈하지 않습니다. 이것은 종종 프로그램을 충돌시키는 오류를 잡는 데 사용됩니다.


2

짧게 (!) : 변수를 선언하고 변수가 값을 보유하고 있는지 확인한 후.

let assumedString: String! = "Some message..."
let implicitString: String = assumedString

그렇지 않으면 가치를 전달 한 후에 마다이 작업을 수행해야합니다 ...

let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation mark

1

John은 선택적인 Person이므로 값을 보유하거나 nil 일 수 있습니다.

john.apartment = number73

john이 선택 사항이 아닌 경우에 사용됩니다. john은 절대로 유효하지 않기 때문에 우리는 그것이 절대 값으로 아파트를 호출하지 않을 것을 확신 할 수 있습니다. 동안

john!.apartment = number73

컴파일러에게 john이 0이 아니라는 것을 약속 한 다음 john의 가치를 얻기 위해 옵션을 풀고 john의 아파트에 액세스합니다. john이 0이 아님을 알고있는 경우이를 사용하십시오. nil 옵션으로 이것을 호출하면 런타임 오류가 발생합니다.

이 문서에는 변환 번호가 선택 사항 인이 예제를 사용하는 좋은 예가 있습니다.

if convertedNumber {
    println("\(possibleNumber) has an integer value of \(convertedNumber!)")
} else {
    println("\(possibleNumber) could not be converted to an integer")
}

당신은 john이 nil이고, 내가 가면 john.apartment = number73'!'를 넣지 않으면 오류가 발생하지 않는다고 말하고 있습니까? 존 후?
Troy

john이 선택 사항 인 경우 컴파일러에서 느낌표를 사용하여 속성에 액세스해야합니다. 컴파일러는 그것이 0이 아님을 알아야하기 때문입니다. 선택 사항이 아닌 경우 느낌표를 사용할 수 없습니다.
코너

1
모든 선택적 var에 느낌표를 사용해야하는 경우 느낌표가 없기 때문에 Apple이 왜 그것을 신경 쓰지 않았 습니까? 불필요 한 팽창처럼 보입니다 ... 또는 선택적 var와 함께 느낌표를 사용하지 않는 것이 합리적입니까?
Troy

선택 사항이 0이 아닌 느낌표를 사용해야 할 때 느낌표를 사용합니다. john의 속성에 액세스하는 경우와 같습니다. var jack : Person과 같은 것을 할 수 있습니까? = john 여기서 jack은 선택적 또는 var jack입니다. Person = john! 여기서 jack은 Person이고 nil이 아닙니다
Connor

그렇습니다. 원래 예제에서 john옵션을 참조하고 있다는 사실이 컴파일러에 0이 아닌 것이 필요하다는 것을 알려주지 var jack: Person = john!않습니까? After Person은 컴파일러에게 넌이 john아닌가? 전반적으로, 그것은 !단지 일종의 불필요한 것 같습니다 ... 그것은 여전히 ​​"왜"부분에 뭔가 빠진 것 같은 느낌이 !...
Troy

1

간단히 말하면 느낌표는 선택 사항이 래핑되지 않음을 의미합니다. 선택 사항은 값을 가질 수있는 변수입니다. 따라서 here let 문 사용하여 변수가 비어 있는지 확인한 다음 강제로 줄 바꿈을 해제 할 수 있습니다. 빈 옵션을 강제로 풀면 프로그램이 중단되므로주의하십시오! 옵션은 변수에 대한 명시 적 할당 끝에 물음표를 붙여 선언합니다. 예를 들어 다음과 같이 쓸 수 있습니다.

var optionalExample: String?

이 변수에는 값이 없습니다. 줄 바꿈을 해제하면 프로그램이 중단되고 Xcode는 nil 값으로 옵션을 줄 바꿈하려고한다고 알려줍니다.

도움이 되었기를 바랍니다.


1

간단한 말로

느낌표를 사용하면 변수가 nil이 아닌 값으로 구성되어야 함을 나타냅니다.


1

전체 이야기는 선택적 vars라는 신속한 기능으로 시작됩니다. 이들은 값을 가지거나 가질 수없는 변수들입니다. 일반적으로 swift는 초기화되지 않은 변수를 사용할 수 없습니다. 이로 인해 충돌이나 예기치 않은 이유가 발생할 수 있으며 백도어에 대한 자리 표시자를 서버에 배치 할 수 있습니다. 따라서 값이 처음 결정되지 않은 변수를 선언하기 위해 '?'를 사용합니다. 그러한 변수가 선언 될 때, 일부 표현식의 일부로 사용하기 전에 사용하기 전에 랩핑을 해제해야하는 경우, 랩핑 해제는 변수의 값이 발견되는 조작으로, 이는 오브젝트에 적용됩니다. unwrapping하지 않고 사용하려고하면 컴파일 시간 오류가 발생합니다. 선택적 var 인 변수를 풀려면 느낌표 "!" 사용.

이제 이러한 선택적 변수에 시스템이나 예를 들어 자체 프로그램에 의해 값이 할당되지만 나중에 "예 : UI 출구"와 같이 물음표 "?" 우리는 사용 "!".

따라서 시스템은 "!"로 선언 된이 변수를 알고 있습니다 현재 선택 사항이며 가치가 없지만 나중에 수명이 다한 값을받습니다.

따라서 느낌표는 두 가지 용도로 사용됩니다. 1. 선택적인 변수를 선언하고 나중에 값을 확실히받습니다. 2. 선택적 변수를 표현식에 사용하기 전에 포장을 풉니 다.

위의 설명은 너무 많은 기술적 인 것을 피합니다.


1

옵션으로 사용하면 옵션을 풀고 무언가가 있는지 확인합니다. if-else 문에서 사용하면 NOT 코드입니다. 예를 들어

if (myNumber != 3){
 // if myNumber is NOT 3 do whatever is inside these brackets.
)

1

선택적 변수는 값을 포함하거나 포함하지 않을 수 있습니다

사례 1 : var myVar:String? = "Something"

사례 2 : var myVar:String? = nil

이제 myVar!를 요청하면 컴파일러에게 1의 경우 값을 반환하도록 지시합니다. "Something"

2의 경우 충돌이 발생합니다.

의미합니다! mark는 컴파일러에 값이없는 경우에도 값을 반환하도록합니다. 그것이 바로 Force Unwrapping 이라는 이름 입니다.


@ 모리츠. 나도 몰라? 질문에 이미 답변이 되었습니까? 문제가 발생하거나 답변에 문제가 있습니까? 이해할 수없는 이유는 무엇입니까? 나는 그 개념에 대한 나의 이해를 바탕으로 대답하려고 노력했다. 어떤 사람들은 명확하고 쉬운 설명에 도움이 될 것이라고 생각합니다.
Ashish Pisey

@Moritz 이제 이것은 건설적입니다. 이것이 바로 그 이유라면, 먼저이 수정 사항을 알려 주어야합니다. 피드백을 주셔서 감사합니다. 나는 그것을 고쳤다.
Ashish Pisey

0
Simple the Optional variable allows nil to be stored.

var str : String? = nil

str = "Data"

To convert Optional to the Specific DataType, We unwrap the variable using the keyword "!"

func get(message : String){
   return
}

get(message : str!)  // Unwapped to pass as String

1
이전 답변에서 아직 다루지 않은 내용을 추가하지 않은 답변은 작성하지 마십시오.
Dalija Prasnikar

-1

자신에게 물어

  • 유형 person?apartment 회원 / 재산이 있습니까? 또는
  • 유형 personapartment회원 / 재산이 있습니까?

이 질문에 대답 할 수 없으면 계속 읽으십시오.

이해하려면 Generics 에 대한 초급 수준의 이해가 필요할 수 있습니다 . 여기를 참조 하십시오 . Swift의 많은 것들이 Generics를 사용하여 작성되었습니다. 옵션 포함

아래 코드는 이 Stanford 비디오 에서 제공되었습니다. . 처음 5 분을 시청할 것을 적극 권장합니다.

Optional은 2 개의 케이스 만있는 열거 형입니다.

enum Optional<T>{
    case None
    case Some(T)
}

let x: String? = nil //actually means:

let x = Optional<String>.None

let x :String? = "hello" //actually means:

let x = Optional<String>.Some("hello")

var y = x! // actually means:

switch x {
case .Some(let value): y = value
case .None: // Raise an exception
}

선택적 바인딩 :

let x:String? = something
if let y = x {
    // do something with y
}
//Actually means:

switch x{
case .Some(let y): print)(y) // or whatever else you like using 
case .None: break
}

당신이 말할 때 당신은 var john: Person?실제로 그런 의미합니다 :

enum Optional<Person>{
case .None
case .Some(Person)
}

위의 열거는 있습니까 특성 이름을 apartment? 어디서나 보입니까? 그건 아니 전혀 거기! 그러나 당신이 그것을 풀면 즉 person!, 할 수 있다면 ... 후드에서하는 일은 다음과 같습니다.Optional<Person>.Some(Person(name: "John Appleseed"))


var john: Person대신에 정의한 경우 : var john: Person?더 이상 !사용 Person하지 않아도됩니다.apartment


!언 랩핑을 사용 하는 것이 때때로 권장되지 않는 이유에 대한 향후 토론 으로이 Q & A를 참조하십시오 .


2
위 의 실제 슬라이드를 사용 하면 저작권이 침해 될 수 있습니다. "... Stanford University는 iTunes U 모음의 모든 컨텐츠에 대한 저작권을 보유합니다." 에서 http://itunes.stanford.edu . 아마 당신이이 질문에 대답하기 위해 인식하는 과정에서 배운 내용에 대해 대답하는 것이 더 좋습니다 (슬라이드를 사용하는 대신 , 참조로 자연스럽게 코드 형식으로 관련 부분을 인용하십시오 ).
dfri

2
당신의 주장은 argumentum ad populum 입니다. 어쨌든, 스탠포드가 여기에 와서 DMCA 권리를 집행 할 것이라고는 생각하지 않지만 , 귀하의 답변이 공식 / 유효한 출처를 기반으로 한 자신의 말로 되어 있고 위와 같이 그 출처를 완전히 복사하는 형태가 아니라면 항상 더 좋습니다 . 특히 저작권이있는 슬라이드에 대해 이야기 할 때 : 코드 블록으로 슬라이드의 내용을 인용하는 것이 좋습니다 (코드 이미지는 일반적으로 여기에서 전혀 없습니다!).
dfri

1
내가 링크 한 메타 게시물은 이것에 대한 SO :의 접근 방식을 설명합니다. 여기에 와야했으며 삭제 될 게시물이 그러하기 때문에 게시물 시행해야합니다. 따라서 나는 썼다 " 나는 믿지 않는다 스탠포드가 여기 와서 ... DMCA의 권리를 행사한다" . 위의 요점은 이것이 저작권 침해 일 가능성이 있다고 생각하지만 (내가 틀렸다고 생각하는) 자연스럽게 아무도 이것을 시행하지 않을 것입니다. ...
dfri

1
그러나 코드 이미지가 포함 된 질문이나 답변을 게시 하는 것은 여러 가지 이유로 권장하지 않습니다 . 결론 : 나는 현재의 형태 로이 답변이 두 가지 주요 이유 (저작권 슬라이드, 코드 이미지)로 인해 그다지 좋지 않다고 생각하는 의견을 지적하려고 노력했습니다. 당연히 나 자신을 포함하여 아무도 이것에 대해 아무것도하지 않을 것입니다. 나는 나중에 참조 할 수 있도록 단순히 지적하고 있습니다 (또는 대신 코드 블록으로 인용 하여이 게시물을 편집하도록 권장합니다). 합의, iTunes U! :)
dfri

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