에서 애플의 설명서 :
및를 함께 사용
if
하여let
누락 될 수있는 값으로 작업 할 수 있습니다. 이 값은 옵션으로 표시됩니다. 선택적 값은 값을 포함하거나nil
값이 누락되었음을 표시하기 위해 포함 합니다.?
값 유형 뒤에 물음표 ( )를 써서 값을 옵션으로 표시하십시오.
왜 선택적 값을 사용하고 싶습니까?
답변
Swift의 옵션은 값을 보유하거나 보유하지 않는 유형입니다. 옵션은 ?
모든 유형에 a 를 추가하여 작성됩니다 .
var name: String? = "Bertie"
선택 사항 (제네릭과 함께)은 이해하기 가장 어려운 Swift 개념 중 하나입니다. 그것들이 어떻게 작성되고 사용되는지에 따라, 그들이 무엇인지 잘못 이해하기 쉽습니다. 위의 옵션을 비교하여 일반 문자열을 만듭니다.
var name: String = "Bertie" // No "?" after String
구문에서 선택적 String은 일반 String과 매우 유사합니다. 그렇지 않습니다. 선택적 문자열은 일부 “선택적”설정이 설정된 문자열이 아닙니다. 특별한 다양한 문자열이 아닙니다. 문자열과 선택적 문자열은 완전히 다른 유형입니다.
알아야 할 가장 중요한 사항은 다음과 같습니다. 옵션은 일종의 컨테이너입니다. 선택적 String은 String을 포함 할 수있는 컨테이너입니다. 선택적 Int는 Int를 포함 할 수있는 컨테이너입니다. 선택 사항을 일종의 소포로 생각하십시오. 당신이 그것을 열기 전에 (또는 선택의 언어로 “포장 풀기”) 당신은 그것이 무엇인가 포함되어 있는지 알 수 없습니다.
Swift 파일에 “선택 사항”을 입력하고 ⌘- 클릭하면 Swift 표준 라이브러리에서 선택 사항이 어떻게 구현되는지 확인할 수 있습니다 . 정의의 중요한 부분은 다음과 같습니다.
enum Optional<Wrapped> {
case none
case some(Wrapped)
}
옵션은 단지입니다 enum
이가지 경우 하나가 될 수있다 : .none
나 .some
. 이 경우 .some
위의 예에서 String
“Hello” 가되는 관련 값이 있습니다 . 선택 사항은 Generics를 사용하여 연관된 값에 유형을 제공합니다. 옵션 문자열의 형식은 아닙니다 String
그것의, Optional
또는 더 정확하게 Optional<String>
.
Swift가 옵션을 사용하여 수행하는 모든 작업은 읽기 및 쓰기 코드를보다 유창하게 만드는 마법입니다. 불행히도 이것은 실제로 작동하는 방식을 모호하게합니다. 나중에 몇 가지 요령을 살펴 보겠습니다.
참고 : 선택적 변수에 대해 많이 이야기 할 것이지만 선택적 상수도 만드는 것이 좋습니다. 생성되는 유형 유형을 이해하기 쉽도록 모든 변수를 유형으로 표시하지만 자신의 코드에는 필요하지 않습니다.
옵션을 만드는 방법
선택 사항을 만들려면 ?
줄 바꿈하려는 유형 뒤에를 추가하십시오 . 모든 유형은 선택 사항 일 수 있으며 심지어 자신의 사용자 정의 유형일 수도 있습니다. 유형과 사이에 공백을 둘 수 없습니다 ?
.
var name: String? = "Bob" // Create an optional String that contains "Bob"
var peter: Person? = Person() // An optional "Person" (custom type)
// A class with a String and an optional String property
class Car {
var modelName: String // must exist
var internalName: String? // may or may not exist
}
옵션 사용
선택 사항을 비교하여 nil
값이 있는지 확인할 수 있습니다 .
var name: String? = "Bob"
name = nil // Set name to nil, the absence of a value
if name != nil {
print("There is a name")
}
if name == nil { // Could also use an "else"
print("Name has no value")
}
약간 혼란 스럽다. 선택 사항은 하나 또는 다른 것임을 의미합니다. nil이거나 “Bob”입니다. 이것은 사실이 아니며, 옵션은 다른 것으로 변형되지 않습니다. 코드를 nil과 비교하는 것은 읽기 쉬운 코드를 만드는 속임수입니다. 선택 사항이 nil 인 경우 열거 형이 현재로 설정되어 있음을 의미합니다 .none
.
옵션 만 사용할 수 있습니다
비 선택적 변수를 nil로 설정하려고하면 오류가 발생합니다.
var red: String = "Red"
red = nil // error: nil cannot be assigned to type 'String'
옵션을 보는 또 다른 방법은 일반적인 Swift 변수를 보완하는 것입니다. 그것들은 값을 갖도록 보장되는 변수에 대응합니다. 스위프트는 모호성을 싫어하는 신중한 언어입니다. 대부분의 변수는 옵션이 아닌 것으로 정의되지만 때로는 불가능합니다. 예를 들어, 캐시 또는 네트워크에서 이미지를로드하는 뷰 컨트롤러를 상상해보십시오. 뷰 컨트롤러가 생성 될 때 이미지가있을 수도 있고 없을 수도 있습니다. 이미지 변수의 값을 보장 할 방법이 없습니다. 이 경우 선택 사항으로 만들어야합니다. nil
이미지가 검색 될 때 시작되고 옵션이 값을 가져옵니다.
옵션을 사용하면 프로그래머의 의도가 드러납니다. 객체가 없을 수있는 Objective-C와 비교하여 Swift는 값이 누락 될 수있는 시점과 존재가 보장되는 시점을 명확히해야합니다.
옵션을 사용하려면 “포장 풀기”
String
실제 위치 대신 옵션을 사용할 수 없습니다 String
. 래핑 된 값을 옵션 내에서 사용하려면 래핑 해제해야합니다. 선택 사항을 랩핑 해제하는 가장 간단한 방법 !
은 선택적 이름 다음 에 추가하는 것입니다. 이것을 “강제 풀기”라고합니다. 선택 사항 내부의 값 (원래 유형으로)을 리턴하지만 선택 사항이 nil
인 경우 런타임 충돌이 발생합니다. 포장을 풀기 전에 값이 있는지 확인해야합니다.
var name: String? = "Bob"
let unwrappedName: String = name!
print("Unwrapped name: \(unwrappedName)")
name = nil
let nilName: String = name! // Runtime crash. Unexpected nil.
선택 사항 확인 및 사용
포장을 풀고 옵션을 사용하기 전에 항상 nil을 확인해야하므로 다음과 같은 일반적인 패턴이 있습니다.
var mealPreference: String? = "Vegetarian"
if mealPreference != nil {
let unwrappedMealPreference: String = mealPreference!
print("Meal: \(unwrappedMealPreference)") // or do something useful
}
이 패턴에서 값이 존재하는지 확인한 다음 값이 확실하면 사용하기 위해 임시 상수로 강제 랩 해제합니다. 이것이 일반적인 일이기 때문에 Swift는 “if let”을 사용하여 지름길을 제공합니다. 이것을 “선택적 바인딩”이라고합니다.
var mealPreference: String? = "Vegetarian"
if let unwrappedMealPreference: String = mealPreference {
print("Meal: \(unwrappedMealPreference)")
}
이것은 임시 상수 (또는 변수를 바꿀 경우 생성 let
과 var
그 범위에서만 경우의 괄호 안에 참조). “unwrappedMealPreference”또는 “realMealPreference”와 같은 이름을 사용해야하는 부담이 있으므로 Swift를 사용하면 원래 변수 이름을 재사용하여 대괄호 범위 내에 임시 이름을 만들 수 있습니다.
var mealPreference: String? = "Vegetarian"
if let mealPreference: String = mealPreference {
print("Meal: \(mealPreference)") // separate from the other mealPreference
}
다음은 다른 변수가 사용됨을 보여주는 코드입니다.
var mealPreference: String? = "Vegetarian"
if var mealPreference: String = mealPreference {
print("Meal: \(mealPreference)") // mealPreference is a String, not a String?
mealPreference = "Beef" // No effect on original
}
// This is the original mealPreference
print("Meal: \(mealPreference)") // Prints "Meal: Optional("Vegetarian")"
선택적 바인딩은 선택적이 nil인지 확인하여 작동합니다. 그렇지 않은 경우 옵션을 제공된 상수로 풀고 블록을 실행합니다. Xcode 8.3 이상 (Swift 3.1)에서 이와 같은 옵션을 인쇄하려고하면 쓸모없는 경고가 발생합니다. 옵션을 사용하여 debugDescription
침묵 시키십시오.
print("\(mealPreference.debugDescription)")
옵션은 무엇입니까?
옵션에는 두 가지 사용 사례가 있습니다.
- 실패 할 수있는 것 (무엇을 기대했지만 아무것도 얻지 못했습니다)
- 지금은 아니지만 나중에있을 수있는 것들 (그리고 그 반대)
구체적인 예 :
- 클래스 와 같이
middleName
또는 클래스spouse
에 있을 수있는 속성Person
- 배열에서 일치하는 항목을 검색하는 것과 같이 값을 반환하거나 아무것도 반환하지 않는 메서드
- 파일의 내용을 읽으려고 시도하는 것처럼 (결과적으로 파일의 데이터를 반환하지만) 파일이 존재하지 않는 것처럼 결과를 반환하거나 오류를 가져 와서 아무것도 반환하지 않는 방법
- 항상 설정할 필요는 없으며 일반적으로 초기화 후에 설정되는 위임 속성
- 대한
weak
클래스의 속성. 그들이 가리키는 것은nil
언제든지 설정할 수 있습니다 - 메모리를 확보하기 위해 해제해야하는 큰 자원
- 별도의 데이터를 사용하는 대신 값이 설정되었는지 (데이터가 아직로드되지 않은 경우> 데이터)를 알아야하는 방법이 필요한 경우
Boolean
Objective-C에는 옵션이 없지만 nil을 반환하는 동등한 개념이 있습니다. 객체를 리턴 할 수있는 메소드는 대신 nil을 리턴 할 수 있습니다. 이것은 “유효한 개체가 없음”을 의미하는 것으로 종종 무언가 잘못되었다고 말하는 데 사용됩니다. 프리미티브 또는 기본 C 유형 (열거 형, 구조체)이 아닌 Objective-C 객체에서만 작동합니다. 오브젝티브 C는 종종 이러한 값의 부재 나타내는 유형을 전문화했다 ( NSNotFound
정말 NSIntegerMax
, kCLLocationCoordinate2DInvalid
좌표 잘못된 표현하기 위해, -1
또는 부정적인 값도 사용된다). 코더는 이러한 특수 값에 대해 알아야하므로 각 경우에 대해 문서화하고 학습해야합니다. 메소드가 nil
매개 변수로 사용할 수없는 경우 이를 문서화해야합니다. Objective-C에서nil
모든 객체가 포인터로 정의되었지만 nil
특정 (0) 주소를 가리키는 것처럼 포인터 였습니다. Swift에서 nil
리터럴은 특정 유형이 없음을 의미합니다.
비교 nil
당신은 옵션을 다음과 같이 사용할 수있었습니다 Boolean
:
let leatherTrim: CarExtras? = nil
if leatherTrim {
price = price + 1000
}
최신 버전의 Swift에서는을 사용해야 leatherTrim != nil
합니다. 왜 이런거야? 문제는 Boolean
옵션으로 포장 할 수 있다는 것입니다. 당신이 Boolean
이것을 좋아 한다면 :
var ambiguous: Boolean? = false
여기에는 값이없는 값과 값이있는 값의 두 종류의 “거짓”이 false
있습니다. Swift는 애매 모호함을 싫어하므로 이제 선택 사항을 항상 확인해야합니다 nil
.
옵션의 요점이 무엇인지 궁금 할 수 Boolean
있습니까? 다른 옵션과 마찬가지로 .none
상태는 값을 아직 알 수 없음을 나타낼 수 있습니다. 네트워크 호출의 다른 쪽 끝에는 폴링하는 데 약간의 시간이 걸릴 수 있습니다. 선택적 부울은 ” 세 값 부울 ” 이라고도합니다.
스위프트 트릭
Swift는 옵션을 사용하기 위해 몇 가지 트릭을 사용합니다. 이 세 줄의 보통처럼 보이는 선택적 코드를 고려하십시오.
var religiousAffiliation: String? = "Rastafarian"
religiousAffiliation = nil
if religiousAffiliation != nil { ... }
이 줄들 중 어느 것도 컴파일해서는 안됩니다.
- 첫 번째 줄은 두 가지 다른 유형 인 문자열 리터럴을 사용하여 선택적 문자열을 설정합니다. 이
String
유형이 다른 경우에도 - 두 번째 줄은 선택적인 문자열을 두 가지 다른 유형 인 nil로 설정합니다.
- 세 번째 줄은 선택적 문자열을 두 가지 유형의 nil과 비교합니다.
이 라인이 작동하도록하는 옵션의 구현 세부 사항 중 일부를 살펴 보겠습니다.
옵션 만들기
?
Swift 컴파일러가 활성화 한 구문 설탕은 선택적인 옵션을 만드는 데 사용 됩니다. 먼 길을 가고 싶다면 다음과 같이 옵션을 만들 수 있습니다.
var name: Optional<String> = Optional("Bob")
이것은 Optional
첫 번째 이니셜 라이저를 호출 public init(_ some: Wrapped)
하여 괄호 안에 사용 된 유형에서 선택 사항의 연관된 유형을 유추합니다.
옵션을 만들고 설정하는 더 긴 방법 :
var serialNumber:String? = Optional.none
serialNumber = Optional.some("1234")
print("\(serialNumber.debugDescription)")
에 옵션 설정 nil
초기 값이없는 옵션을 만들거나 초기 값이 같은 옵션을 만들 수 있습니다 nil
(둘 다 동일한 결과를 가짐).
var name: String?
var name: String? = nil
nil
프로토콜 ExpressibleByNilLiteral
(이전의 이름 NilLiteralConvertible
) 은 옵션을 동일하게 허용 합니다. 옵션은 Optional
두 번째 이니셜 라이저 인으로 생성됩니다 public init(nilLiteral: ())
. 문서에서는 ExpressibleByNilLiteral
선택 사항을 제외하고는 코드에서 nil의 의미를 바꿀 수 있기 때문에 선택 사항을 제외하고 는 사용해서는 안된다고 말합니다 .
class Clint: ExpressibleByNilLiteral {
var name: String?
required init(nilLiteral: ()) {
name = "The Man with No Name"
}
}
let clint: Clint = nil // Would normally give an error
print("\(clint.name)")
동일한 프로토콜을 사용하여 이미 작성된 옵션을로 설정할 수 있습니다 nil
. 권장하지는 않지만 nil 리터럴 이니셜 라이저를 직접 사용할 수 있습니다.
var name: Optional<String> = Optional(nilLiteral: ())
옵션과 비교 nil
선택 사항은 정의에서 볼 수있는 두 개의 특수 “==”및 “! =”연산자를 Optional
정의합니다. 첫 번째 ==
옵션은 선택 사항이 nil인지 확인합니다. .none으로 설정된 두 개의 다른 옵션은 연결된 유형이 동일한 경우 항상 동일합니다. nil과 비교할 때 장면 뒤에서 Swift는 동일한 연관된 유형의 옵션을 작성하고 .none으로 설정 한 다음 비교에 사용합니다.
// How Swift actually compares to nil
var tuxedoRequired: String? = nil
let temp: Optional<String> = Optional.none
if tuxedoRequired == temp { // equivalent to if tuxedoRequired == nil
print("tuxedoRequired is nil")
}
두 번째 ==
연산자를 사용하면 두 가지 옵션을 비교할 수 있습니다. 둘 다 동일한 유형이어야하고 해당 유형을 준수해야합니다 Equatable
(일반 “==”연산자와 비교할 수있는 프로토콜). 스위프트 (아마도) 두 값을 풀고 직접 비교합니다. 또한 선택 사항 중 하나 또는 둘 다가 인 경우도 처리합니다 .none
. nil
리터럴 과 비교하는 것의 차이점에 유의하십시오 .
또한 모든 Equatable
유형을 선택적 유형의 포장 과 비교할 수 있습니다 .
let numberToFind: Int = 23
let numberFromString: Int? = Int("23") // Optional(23)
if numberToFind == numberFromString {
print("It's a match!") // Prints "It's a match!"
}
뒤에서 Swift는 비교하기 전에 비 선택 사항을 선택 사항으로 래핑합니다. 리터럴과도 작동합니다 ( if 23 == numberFromString {
)
나는 두 개의 ==
연산자 가 있다고 말 했지만 실제로 nil
비교의 왼쪽 에 넣을 수있는 세 번째 연산자 가 있습니다.
if nil == name { ... }
명명 옵션
선택적 유형의 이름을 비 선택적 유형과 다르게 지정하는 스위프트 규칙은 없습니다. 사람들은 이름에 선택 사항 ( “optionalMiddleName”또는 “possibleNumberAsString”)을 표시하기 위해 이름에 무언가를 추가하지 말고 선언이 선택 사항 유형임을 표시하도록하십시오. 선택 사항에서 값을 보유 할 이름을 지정하려는 경우 어려움이 있습니다. “middleName”이라는 이름은 이것이 문자열 유형임을 의미하므로 문자열 값을 추출 할 때 종종 “actualMiddleName”또는 “unwrappedMiddleName”또는 “realMiddleName”과 같은 이름으로 끝날 수 있습니다. 선택적 바인딩을 사용하고 변수 이름을 재사용하여이 문제를 해결하십시오.
공식적인 정의
Swift는 또한 값이없는 것을 처리하는 선택적 유형을 도입했습니다. 선택 사항은 “값이 있고 x와 같습니다”또는 “값이 전혀 없습니다”라고 말합니다. 선택 사항은 Objective-C에서 포인터로 nil을 사용하는 것과 유사하지만 클래스뿐만 아니라 모든 유형에서 작동합니다. 옵션은 Objective-C의 nil 포인터보다 안전하고 표현력이 뛰어나며 Swift의 가장 강력한 기능의 핵심입니다.
선택 사항은 Swift가 유형이 안전한 언어라는 사실의 예입니다. Swift를 사용하면 코드에서 사용할 수있는 값 유형을 명확하게 파악할 수 있습니다. 코드의 일부에 문자열이 필요한 경우 형식 안전으로 인해 실수로 Int를 전달할 수 없습니다. 이를 통해 개발 프로세스에서 가능한 빨리 오류를 포착하고 수정할 수 있습니다.
마무리하기 위해 다음은 옵션에 대한 1899의시입니다.
어제 계단에
나는 없었다 사람이 만난
그는이 오늘 다시 아니었다
내가 원하는, 나는 그가 멀리 가고 싶어 할
Antigonish을
추가 자료 :
답변
의는의 예를 보자 NSError
당신이 무기 호를 반환하는 선택하게 할 것 반환되는 오류가없는 경우. 오류가 없으면 값을 할당 할 필요가 없습니다.
var error: NSError? = nil
또한 기본값을 가질 수 있습니다. 따라서 함수에 아무것도 전달되지 않으면 메소드에 기본값을 설정할 수 있습니다
func doesntEnterNumber(x: Int? = 5) -> Bool {
if (x == 5){
return true
} else {
return false
}
}
답변
nil
Swift에서 가리키는 변수를 가질 수 없습니다 . 포인터와 널 포인터가 없습니다. 그러나 API에서는 종종 특정 종류의 값 또는 부족한 값을 나타낼 수 있기를 원합니다. 예를 들어, 내 창에 대리인이 있습니까? 그렇다면 누구입니까? 선택 사항은 Swift의 형식 안전, 메모리 안전 방법입니다.
답변
나는 초보자로서 내 머리에 있었던 불확실성을 없애기 위해 위의 대부분을 요약 한 짧은 대답을했다.
Objective-C와 달리 Swift 에는 nil 을 포함 할 수있는 변수가 없으므로 Optional 변수 유형이 추가되었습니다 ( “?”로 접미어가있는 변수).
var aString = nil //error
큰 차이는 선택적 변수가 바로 여기에 포함 (일반의 Obj-C 변수처럼) 값을 저장하지 않는 것이 두 가지 상태 ” 값을 갖는다 “또는 ” 전무가 “
var aString: String? = "Hello, World!"
aString = nil //correct, now it contains the state "has nil"
즉, 다른 상황에서 해당 변수를 확인할 수 있습니다.
if let myString = aString? {
println(myString)
}
else {
println("It's nil") // this will print in our case
}
“!”를 사용함으로써 접미사로 묶인 경우에만 래핑 된 값에 액세스 할 수 있습니다 . (즉, nil 이 아님 ) :
let aString: String? = "Hello, World!"
// var anotherString: String = aString //error
var anotherString: String = aString!
println(anotherString) //it will print "Hello, World!"
그래서 “?”를 사용해야합니다. 그리고 “!” 기본적으로 모두 사용하지는 않습니다. (이것은 나의 가장 큰 당황이었다)
나는 또한 위의 답변에 동의합니다 : 선택적 유형은 부울로 사용할 수 없습니다 .
답변
값이없는 객관적인 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
{..}
답변
선택적 값을 사용하면 값이 없음을 표시 할 수 있습니다. SQL의 NULL 또는 Objective-C의 NSNull과 약간 비슷합니다. “기본”유형에도 사용할 수 있기 때문에 이것이 개선 될 것 같습니다.
// Reimplement the Swift standard library's optional type
enum OptionalValue<T> {
case None
case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)”
발췌 : Apple Inc.“Swift Programming Language.” iBooks. https://itun.es/gb/jEUH0.l
답변
선택 사항은 값이 유형에 해당하는지 Swift가 완전히 확실하지 않음을 의미합니다 (예 : Int? Swift는 숫자가 Int인지 완전히 확신하지 못합니다.
이를 제거하기 위해 사용할 수있는 세 가지 방법이 있습니다.
1) 유형이 완전히 확실하면 느낌표를 사용하여 다음과 같이 강제로 줄 바꿈을 해제 할 수 있습니다.
// Here is an optional variable:
var age: Int?
// Here is how you would force unwrap it:
var unwrappedAge = age!
옵션을 강제로 줄 바꿈 해제하고 nil과 같으면 다음과 같은 충돌 오류가 발생할 수 있습니다.
이것이 반드시 안전하지는 않으므로 다음과 같은 유형과 값을 확신 할 수없는 경우 충돌을 방지 할 수있는 방법이 있습니다.
방법 2와 3은이 문제를 방지합니다.
2) 암시 적으로 래핑되지 않은 옵션
if let unwrappedAge = age {
// continue in here
}
래핑되지 않은 유형은 이제 Int 가 아닌 Int입니까? .
3) 가드 진술
guard let unwrappedAge = age else {
// continue in here
}
여기서부터 래핑되지 않은 변수를 사용할 수 있습니다. 변수 유형이 확실하면 랩 해제 (!로) 만 강제 실행하십시오.
프로젝트와 함께 행운을 빕니다!