λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
🍏 Today I Learned/Swift 문법

[Swift] μ˜΅μ…”λ„

by Joseph Seong 2023. 12. 6.

 

 

 

μ˜΅μ…”λ„

 

 

μ˜΅μ…”λ„ (Optional)

 

  • 값이 없을 수 μžˆλŠ” μƒν™©μ—μ„œ μ˜΅μ…”λ„(Optional)을 μ‚¬μš©
  • μ˜΅μ…”λ„μ€ λ¬ΌμŒν‘œ ? 둜 λ‚˜νƒ€λ‚Έλ‹€. (νƒ€μž… μ–΄λ…Έν…Œμ΄μ…˜)
  • μ˜΅μ…”λ„μ€ 두 κ°€μ§€ κ°€λŠ₯성을 λ‚˜νƒ€λ‚Έλ‹€.
    • 값이 있고 μ˜΅μ…”λ„λ‘œ λž˜ν•‘(wrapping)해놓은 값을 μ–Έλž˜ν•‘(unwrapping)ν•˜μ—¬ ν•΄λ‹Ή 값에 μ•‘μ„ΈμŠ€ν•  수 μžˆλ‹€.
    • 값이 μ „ν˜€ μ—†λ‹€.
  • μ˜΅μ…”λ„ νƒ€μž…λΌλ¦¬μ˜ 연산은 λΆˆκ°€λŠ₯
// μΆ•μ•½ νƒ€μž… ν‘œν˜„
var serverResponseCode: Int? = 404 
// 정식 νƒ€μž… ν‘œν˜„
var myPetName: Optional<String> = "멍멍이"

func pay(with card: String?) {
   // κ΅¬ν˜„ μ½”λ“œ
}

// μ˜΅μ…”λ„ νƒ€μž…λΌλ¦¬μ˜ 연산은 λΆˆκ°€λŠ₯
var num1: Int? = 4
var num2: Int? = 2

num1 + num2 // μ—λŸ¬ λ°œμƒ!

let optionalString1: String? = "Hello, "
let optionalString2: String? = "world!"

// μ˜΅μ…”λ„ String 값듀을 μ—°κ²°ν•˜λ €λŠ” μ‹œλ„
let result = optionalString1 + optionalString2 // μ—λŸ¬ λ°œμƒ!

 

 

nil

 

  • λ³€μˆ˜μ— nil을 ν• λ‹Ήν•¨μœΌλ‘œμ¨ 값이 μ—†λŠ” μƒνƒœμ˜ μ˜΅μ…”λ„ ν”„λ‘œνΌν‹°λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.
var serverResponseCode: Int? = 404
serverResponseCode = nil

var surveyAnswer: String?
// surveyAnswerλŠ” μžλ™μœΌλ‘œ nil둜 μ„€μ •λœλ‹€.

 

 

μ˜΅μ…”λ„ 바인딩

 

  • μ˜΅μ…”λ„ 바인딩은 μ˜΅μ…”λ„ 값이 λΉˆκ°’μΈμ§€ μ‘΄μž¬ν•˜λŠ”μ§€ κ²€μ‚¬ν•œ ν›„, μ‘΄μž¬ν•˜λŠ” 경우 κ·Έ 값을 λ‹€λ₯Έ λ³€μˆ˜μ— λŒ€μž…μ‹œμΌœ λ°”μΈλ”©ν•˜λŠ” 것을 의미
  • 빈 값을 μ²΄ν¬ν•˜κ³  μ˜΅μ…”λ„ 값을 μ–Έλž˜ν•‘ ν•΄μ£ΌλŠ” 것은 κ°•μ œλ‘œ μ–Έλž˜ν•‘ν•˜λŠ” 것보닀 훨씬 μ•ˆμ „ν•˜λ‹€.
  • if let / if var, guard let / guard var을 μ¨μ„œ μ˜΅μ…”λ„ 값을 μΆ”μΆœν•΄ μƒˆλ‘œμš΄ λ³€μˆ˜μ— λ°”μΈλ”©ν•œλ‹€.
  • if let vs guard let 차이점
    • if let은 if문의 μ½”λ“œ κ΅¬ν˜„λΆ€ λ‚΄μ—μ„œλ§Œ μƒμˆ˜ μ‚¬μš©μ΄ κ°€λŠ₯ν•˜λ‹€.(μ§€μ—­ λ³€μˆ˜)
    • guard let 은 guard문을 ν†΅κ³Όν•œ μƒμˆ˜λ₯Ό guardλ¬Έ λ°–μ—μ„œ μ‚¬μš©μ΄ κ°€λŠ₯ν•˜λ‹€.(μ „μ—­λ³€μˆ˜)
if let <#μƒμˆ˜ 이름#> = <#μ˜΅μ…”λ„ κ°’#> {
   // κ΅¬ν˜„ μ½”λ“œ
}


let roommateNumbers: Int? = nil
if let roommates = roommateNumbers {   // λ°•μŠ€λ₯Ό κΉŒμ„œ roommates에 λ‹΄λŠ” ν–‰μœ„(if let)
    print (roommates)
}
// 좜λ ₯κ°’ μ—†μŒ

let ticketCounts: Int? = 3
if let ticket = ticketCounts {
    print (ticket)
}
// 좜λ ₯κ°’: 3


// μ˜΅μ…”λ„ 바인딩 ν•  λ³€μˆ˜κ°€ μ—¬λŸ¬ 개인 경우
let boyName : String?
let girlName : String?

boyName = "ν•˜λŠ˜"
girlName = "λ‚˜μ—°"

// , 콀마둜 λ‚˜μ—΄ν•©λ‹ˆλ‹€
if let boy = boyName,
   let girl = girlName {
    print(boy, girl)
}
// 좜λ ₯κ°’: ν•˜λŠ˜ λ‚˜μ—°

let x : Int? = 10
let y : Int? = nil

func opbinding() {
    guard let x = x else { return }	// μš°λ³€ xλŠ” μ˜΅μ…”λ„ν•œ κ°’, μ’Œλ³€ xλŠ” μƒˆλ‘œ λ§Œλ“  μƒμˆ˜
    print(x)

    guard let y = y else { return } // yλŠ” nilμ΄λ―€λ‘œ μ—¬κΈ°μ„œ return 
    print(y) // μœ„μ—μ„œ return ν•˜μ˜€κΈ° λ•Œλ¬Έμ— 이 μ½”λ“œ 라인은 μ‹€ν–‰λ˜μ§€ μ•ŠμŒ
}

opbinding()
// 좜λ ₯κ°’: 10

 

 

μ˜΅μ…”λ„ κ°•μ œ μ–Έλž˜ν•‘

 

  • κ°•μ œ μ–Έλž˜ν•‘(Force unwrapping)은 !λ₯Ό μ¨μ„œ κ°•μ œλ‘œ μ˜΅μ…”λ„ μΆ”μΆœ (βœ”οΈ λ³€μˆ˜ μ•žμ— !λ₯Ό λΆ™μ΄λŠ” 것은 not의 의미)
  • κ°•μ œ μ–Έλž˜ν•‘μ„ 잘λͺ» μ‚¬μš©ν•  경우 ν”„λ‘œκ·Έλž¨μ΄ λΉ„μ •μƒμ μœΌλ‘œ μ’…λ£Œλ  μˆ˜λ„ μžˆμœΌλ―€λ‘œ λ°˜λ“œμ‹œ nil이 μ•„λ‹Œ 것이 ν™•μ‹€ν•œ μƒν™©μ—μ„œ μ‚¬μš©ν•΄μ•Όν•œλ‹€. (μ΅œλŒ€ν•œ μ•ˆ μ“°λŠ”κ²Œ μ’‹λ‹€)
let number = Int("42")!
// String값을 Int둜 λ³€ν™˜ν•˜λŠ” ν•¨μˆ˜λŠ” returnκ°’μœΌλ‘œ μ˜΅μ…”λ„ 값을 λ°˜ν™˜ν•œλ‹€.
print(number)
// 좜λ ₯κ°’: 42

// κ°•μ œ μ–Έλž˜ν•‘μ΄ μ‹€νŒ¨ν•œ 경우
let address: String? = nil
print(address!)
// μ—λŸ¬πŸš¨ λ©”μ‹œμ§€: Unexpectedly found nil while unwrapping an Optional value

 

 

μ˜΅μ…”λ„ λ³€μˆ˜μ˜ 값이 nil일 λ•Œλ₯Ό μœ„ν•΄ κΈ°λ³Έκ°’ μ„€μ •ν•˜κΈ°

 

  • 값이 nil일 경우λ₯Ό μœ„ν•΄ 기본값을 μ„€μ •ν•  수 μžˆλ‹€(nil-coalescing)
    • ?? 을 μ‚¬μš©ν•˜μ—¬ 기본값을 μ‚¬μš©ν•  수 μžˆλ‹€. (기본값을 λΆ€μ—¬ν•œ λ³€μˆ˜λŠ” μ˜΅μ…”λ„ νƒ€μž…μ΄ μ•„λ‹ˆλ‹€.)
    • let(var) a = b ?? c ν˜•νƒœλ‘œ μ΄λ£¨μ–΄μ§€λŠ”λ° bλŠ” μ˜΅μ…”λ„ νƒ€μž…μ΄κ³ , bκ°€ nil일 κ²½μš°λŠ” a에 cκ°€ λŒ€μž…λ˜κ³ , nil이 아닐 κ²½μš°μ—λŠ” μ˜΅μ…”λ„μ„ μ œκ±°ν•œ 값이 a에 λŒ€μž…λœλ‹€.
var optNumber: Int? = 3
let number = optNumber ?? 5
print(number) // 좜λ ₯κ°’ : 3
//numberλŠ” Int? νƒ€μž…μ΄ μ•„λ‹ˆλΌ Int νƒ€μž…

optNumber = nil
let number2 = optNumber ?? 5
print(number) // 좜λ ₯κ°’ : 5
//numberλŠ” Int? νƒ€μž…μ΄ μ•„λ‹ˆλΌ Int νƒ€μž…

print(heartPath)
// imagePaths["heart"]κ°€ nil일 λ•Œ 
// 좜λ ₯κ°’: "/images/default.png"

 

 

μ˜΅μ…”λ„ 체이닝

 

  • μ˜΅μ…”λ„μ„ μ—°μ‡„μ μœΌλ‘œ μ‚¬μš©ν•˜λŠ” 것
  • . 을 톡해 λ‚΄λΆ€ ν”„λ‘œνΌν‹°λ‚˜ λ©”μ„œλ“œμ— μ—°μ†μ μœΌλ‘œ μ ‘κ·Όν•  λ•Œ μ˜΅μ…”λ„ 값이 있으면 μ˜΅μ…”λ„ μ²΄μ΄λ‹μœΌλ‘œ μ ‘κ·Όν•  수 μžˆλ‹€.
struct Person {
	var name: String
	var address: Address
}

struct Address {
	var city: String
	var street: String
	var detail: String
}

let sam: Person? = Person(name: "Sam", address: Address(city: "μ„œμšΈ", street: "μ‹ λ…Όν˜„λ‘œ", detail: "100"))
print(sam.address.city) 
// μ—λŸ¬ 🚨. μ—λŸ¬ λ©”μ‹œμ§€: Chain the optional using '?' to access member 'address' only for non-'nil' base values
sam?.address.city  // sam이 μ—†λ‹€λ©΄ .address.cityκ°€ μ‹€ν–‰λ˜μ§€ μ•Šκ³  μžˆλ‹€λ©΄ ν•œλ‹¨κ³„μ”© 타고 λ“€μ–΄κ°„λ‹€. 좜λ ₯κ°’: μ„œμšΈ

 

  • λ§Œμ•½ sam이 μ˜΅μ…”λ„μ΄ μ•„λ‹Œ Person νƒ€μž…μ΄μ—ˆλ‹€λ©΄ sam.address.city κ°€ κ°€λŠ₯ν•˜λ‹€.
  • ν•˜μ§€λ§Œ sam이 μ˜΅μ…”λ„ νƒ€μž…μ΄κΈ° λ•Œλ¬Έμ— address에 μ ‘κ·Όν•˜λ €λ©΄ sam?.address.city ν˜•νƒœλ‘œ 이루어져야 ν•œλ‹€
  • μœ„ μ½”λ“œ 쀑 “sam?.address.city” 을 μ‚΄νŽ΄λ³΄λ©΄, sam == nil 일 경우 μ—λŸ¬κ°€ λ‚˜μ§€ μ•Šκ³  λ’€ μ½”λ“œκ°€ μ‹€ν–‰λ˜μ§€ μ•ŠλŠ”λ‹€.
  • λ‹€λ₯Έ μ–Έμ–΄μ˜ null은 .으둜 μ°Έμ‘°λ₯Ό ν•˜λ©΄ λ°”λ‘œ NullPointerException μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.
  • λ”°λΌμ„œ Swiftμ—μ„œμ˜ nil은 λ©”λͺ¨λ¦¬μ˜ μ£Όμ†Œκ°’μ΄ μ—†μŒμ„ λ‚˜νƒ€λ‚΄λŠ” null이 μ•„λ‹ˆλΌ 값이 μ—†μŒμ„ λ‚˜νƒ€λ‚΄λŠ” κ°’(Enum)이닀.