- swift에 대해 공부한 내용을 정리한 글입니다.
- 해당 글은 한빛미디어의 스위프트 프로그래밍 3판을 참고하여 작성했습니다.
옵셔널은 스위프트의 큰 특징 중 하나인 안전성을 담보로 하는 기능이다. 옵셔널은 단어 뜻 그대로 '선택적인', 즉 값이 '있을 수도 있고, 없을 수도 있음'을 나타내는 표현이다.
var name: String = ""
이렇게 변수를 선언한다면, 빈 문자열이니 name은 값이 없는 변수일까?
정답은 X이다. name 변수는 비어있는 것이 아니라, '비어있는 문자열'이라는 값을 가지고 있다.
var number: Int = 0
이 코드도 마찬가지 이다. number 라는 변수 안에 0이라는 값이 저장되어 있다.
그렇다면 값이 없는 경우는 무엇일까?
var number: Int? = nil
바로 변수가 nil
인 경우이다. nil은 '값이 없음' 을 나타내는 표현으로, 다른 언어의 null
과 동일하다.
var name: String?
var name: String? = "Hoojeong"
일반 변수에 옵셔널 타입 변수를 넣는 거는요??
var requiredName: String = name
Value of optional type 'String?' must be unwrapped to a value of type 'String'
var name: String? = "Hoojeong"
print(name)
Optional("Hoojeong")
결과를 보면 슬쩍 봐도 일반적인 변수와 다르다는 것을 알 수 있다. 마치 옵셔널이라는 포장지에 포장된 것처럼 보인다.
때문에, 옵셔널 타입 변수는 일반 변수와 결합도, 연산도 할 수 없다. 연산을 수행하기 위해서는 옵셔널 바인딩이 필요하다.
옵셔널 타입 변수는 옵셔널이라는 포장지에 싸여 있어, 일반 변수와 그 어떠한 연산도 수행할 수 없다.
연산을 하기 위해서는 옵셔널의 값을 옵셔널이 아닌 값으로 추출 하는 과정을 거쳐야 한다.
옵셔널에서 값을 추출하는 방법은 여러가지가 존재한다.
옵셔널의 강제 추출 방식은 여러 방식 중에서 가장 간단하지만 가장 위험한 방법이다. 옵셔널의 값을 강제 추출하기 위해서는 옵셔널 타입 변수 뒤에 느낌표(!)를 붙이면 된다.
var number: Int? = 3
print(number)
print(number!)
Optional(3)
3
결과를 보면 변수 뒤에 느낌표를 붙이니 감싸고 있던 옵셔널 포장지가 사라진 것을 알 수 있다.
강제 추출 방법은 간단하게 값을 추출할 수 있지만, 만약 변수가 nil인 경우에는 추출할 수 있는 값이 없기 때문에 런타임 에러가 발생한다. 이러한 이유로 잘 사용되지 않는다.
옵셔널의 값을 더욱 안전하게 추출하고 싶다면, 옵셔널 바인딩 방식을 사용한다. 다른 언어에서 if문을 사용해 변수가 null인지를 먼저 확인하는 방식과 유사하다.
if let result = number {
print(result)
} else {
print("number is nil")
}
3
if문의 조건부에서 임시 변수를 할당하여 사용하는 방식이다. if let 이나 if var 를 사용해 만약 옵셔널에 값이 있다면 값을 추출하여 임시 변수에 할당한다.
할당한 변수는 if문의 블록 내에서만 사용할 수 있다. 만약 값이 없다면 else 문을 수행한다.
또한 guard
문을 사용해 옵셔널 바인딩을 할 수 있다.
func test() {
let number: Int? = 5
guard let result = number else {return}
print(result)
}
test()
5
if문을 사용하여 옵셔널 바인딩을 수행하면 if문 내에서만 값을 추출한 변수/상수를 사용할 수 있다. 하지만 guard문을 사용한다면, guard문의 다음 줄부터 함수 끝까지 추출한 변수/상수를 사용할 수 있다.
guard문은 간단하게 조건이 true일 때만 guard문을 수행하고, false일 때는 else 구문을 수행한다. 자세한 내용은 다른 포스팅에서 다루겠다.
옵셔널을 연산자를 사용해 다른 변수와 비교하면, 컴파일러가 자동으로 옵셔널의 값을 추출해주는 방식이다.
let value: Int? = 6
if value == 6 {
print("value = 6")
} else {
print("value != 6")
}
value = 6
묵시적 추출은 옵셔널 타입이지만 옵셔널의 값을 사용할 때는 자동으로 값을 추출해준다. 옵셔널과 달리, 묵시적 추출은 데이터 타입 뒤에 느낌표(!)를 붙여 표현한다.
let string = "12"
var stringToInt: Int! = Int(string)
print(stringToInt + 1)
13
느낌표가 붙어있는 stringToInt 변수는 사용할 때 옵셔널의 값을 묵시적으로 추출하여 일반 변수처럼 자유롭게 사용할 수 있다.
편리해 보이지만, 강제 추출과 동일하게 nil이 할당되어 있을 때 접근을 시도하면 런타임 에러가 발생한다. 때문에 스위프트는 옵셔널 바인딩이나 뒤에서 배울 옵셔널 체이닝 방식을 권장한다.
var stringToInt: Int! = Int(string)
위 코드에서 Int()
함수는 문자열이나 문자 타입의 변수를 정수로 변환해준다. 이때 문자열이 숫자가 아닌 한글이나 영어로 되어있을 때는 정수로 변환할 수 없기 때문에 값이 존재하지 않는다.
즉, Int() 함수에서 반환된 값이 정수일 수도, nil일 수도 있다. 때문에 일반 변수가 아닌, 옵셔널을 사용해야 한다.