Swift 옵셔널(2020.10.28)

K S Michael·2020년 10월 28일

swift TIL

목록 보기
5/29

Optional : 값이 "있을 수도 있고, 없을 수도 있다"

let optionalConstant: Int? = nil
let someConstant: Int = nil 
	// Nil cannot initialize specified type 'Int'

OPtional의 존재 이유
: nil의 가능성을 명시적으로 표현

  • nil 가능성을 문서화 하지 않아도 코드만으로 충분히 표현 가능
  • 문서/주석 작성 시간을 절약
  • 전달받은 값이 옵셔널이 아니라면 nil체크를 하지 않더라도 안심하고 사용
  • 효율적인 코딩
  • 예외 상황을 최소화하는 안전한 코딩
// someOptionalParam can be nil
func someFunction(someOptionalParam:Int?){
 // ...
}
// someParam must not be nil
func someFunction(someParam:Int){
 // ...
}

someFunction(someOptionalOaram:nil)
someFunction(someParam:nil) // 에러:Nil is not compatible with expected argument type 'Int'

아래 코드는 주석을 제외한 위 같은 코드이다.
Optional이 있으면 주석이 없어도 전혀 문제가 되지 않는다.

func someFunction(someOptionalParam:Int?){
 // ...
}
func someFunction(someParam:Int){
 // ...
}

someFunction(someOptionalOaram:nil)
someFunction(someParam:nil) // 에러:Nil is not compatible with expected argument type 'Int'

Optional

enum(열거형) + general

enum Optonal<Wrapped> : ExpressibleByNilLiteral{
	case none
 	case some(Wrapped)
}
 
let optionalValue:Optional<Int> = nil
let optionalValue:Int? = nil

Implicitly Unwrapped Optional 암시적 추출 옵셔널 (!)

var optionalValue: Int! = 100
  
  switch optionalValue{
  	case .none:
  		print("This Optional variable is nil")
  	case .some(let value):
  		print("Value is \(value)")
  }
  
  
//기존 변수처럼 사용 가능
optionalValue = optionalValue +1

// nil 할당 가능
optionalValue = nil

// 잘못된 접근으로 인한 런타임 오류 발생
optionalValue = optionalValue +1 // nil 값을 넣어서 런타임 에러 발생

일반적인 옵셔널 (?)

var optionalValue: Int? = 100
  
  switch optionalValue{
  	case .none:
  		print("This Optional variable is nil")
  	case .some(let value):
  		print("Value is \(value)")
  }
 
// nil 할당 가능
optionalValue = nil
// 기존 변수처럼 사용불가 - 옵셔널과 일반 값은 다른 타입이므로 연산불가
optionalValue = optionalValue + 1

Optional Unwrapping

Optional Binding - 옵셔널 바인딩
Force Unwrapping - 강제 추출

  • Optional Binding

    옵셔널의 값을 꺼내오는 방법 중 하나
    nil 체크 + 안전한 값 추출
    1. 값이 있는지 물어보는 과정
    2. 값이 있으면 꺼내고, 없으면 지나침
func printName ( _ name : String){
	print(name)
}
var myName:String? = nil
printName(myName)
// 전달 되는 값이 nil 이기 대문에 컴파일 오류 발생

위와 같이 nil체크를 하지 않는 다면 에러가 발생할수 있다.
이런 경우에 if-let or if-var으로 nil 체크를 할수 있다.

1개만 바인딩

func printName(_ name: String){
	print(name)
}
var myName : String! = nil
if let name: String = myName {
	printName(name)
} else {
	print("myName == nil)
}
// name 상수는 if-let 구문 내에서만 사용가능하다.
// 상수 사용범위를 벗어났기 때문에 컴파일 오류 발생
printName(name)

1개이상 바인딩

var myName : String? = "yagom"
var yourName: String? = nil

if let name = myName , let friend = yourName {
    print("\(name) and \(friend)")
}
// yourName이 nil 이기때문에 실행되지 않는다.
// 예시에서 처럼 1개 이상의 nil 값이 있는 경우 해당 line은 실행 되지 않는다.

yourName = "haha"

if let name = myName , let friend = yourName {
    print("\(name) and \(friend)")
}
// yagom and haha

바인딩에 대한 나의 생각
바인딩은 nil을 체크하는 조건문과 비슷한것 같다.

Force Unwrapping

func printName(_ name: String){
    print(name)
}

var myName : String? = "Yagom"
printName(myName) // 에러 : (error message)optional로 감싸져있다! 포장 벗겨내고 사용해라!
printName(myName!) // Yagom  .  '!' 를 붙이면 포장을 강제로 벗길수 있다.
// 만약 선언할때 '!'느낌표 옵션으로 넣으면 옵션을 사용하는데 벗겨서 반환한다라는 의미이다.

// 아래 코드는 위 코드와 동일하다.
func printName(_ name: String){
    print(name)
}

var myName : String!
myName="Yagom"

printName(myName)

두가지 방식은 순서의 차이인것 같다.
옵션을 사용할때 벗기는 첫번째 방식과, 번긴다음 할당하는 두번째 방식

myName = nil

print(myName!) // 강제추출시 값이 없으므로 런타임 오류 발생

var yourName: String! = nil // 선언할 때부터 옵션을 벗겨서 전달할 계획이기 때문에 nil '!' 느낌표를 사용했음!

printName(yourName)
// nil 값이 전달되기 때문에 런타임 오류 발생

강제 추출 방식은 추천하는 방식은 아니다. 안전하게 옵셔널을 사용하려면 binding 방식을 사용하는게 좋다.

출처 : 유튜브 "yagom"

profile
차근차근

0개의 댓글