Swift๋ฅผ ์ฒ์ ๊ณต๋ถํ๋ฉด์ ๊ฐ์ฅ ์ด๋ ค์ ๋๊ฒ ์ด Optional์ธ ๊ฒ ๊ฐ๋ค. ์ ์ด์ ๊ฐ๋ฐ๋ ์ฒ์ํ ์๊ธฐ์์ผ๋, ์ด๋ฐ ์๋ฃ๊ตฌ์กฐ๊ฐ ์ ํ์ํ์ง ์ ํ ๋ชฐ๋์๋ ์๊ฐ์ด ์์๋ค. ํด๋น ์ด์ ๋ Either์ Result ์ดํด์ ์ค์ ์ฌ์ฉ์ ์์๋ณด๊ธฐ ํฌ์คํธ๋ฅผ ์ฐธ๊ณ ํด์ฃผ๊ธธ ๋ฐ๋๋ค. ๊ทธ๋ผ, Optional์ ์ ์ฒด์ ๊ถ๊ธํ๋ ์ ์ ์ ๋ฆฌํ๋ ํฌ์คํ ์ ์์ํด๋ณด๋๋ก ํ๊ฒ ๋ค.
Optional
enum Optional<T> {
case none
case some(<T>)
}
// ์ค์ ๋ฌธ์์๋ ์๋์ ๊ฐ์ด ์ ํ ์๋ค. generic ํ์
ํ๋ผ๋ฏธํฐ์ ๋ํด ๋ช
์์ ์ผ๋ก ์ ๊ธฐ ์ํด ์ด๋ ๊ฒ ๋์ด ์๋ค.
enum Optional<Wrapped> {
case none
case some(<Wrapped>)
}
์ผ๋จ, ํต์ฌ์ Optional์ enum์ด๋ผ๋ ๊ฒ์ด๋ค. case ์ด๋ฆ ๋ค์ ()๊ฐ ๋ถ์ ๊ฒ์, ์ด some์ด๋ผ๋ ํน์ ํ์ ์ ๋ํด ์ถ๊ฐ์ ์ธ ์ ๋ณด๋ฅผ ์ ์ฅํ๋ ๋ฐฉ๋ฒ์ด๋ค. ์ด ๊ฒฝ์ฐ๋ ๋ชจ๋ ํ์ ์ ์ธ์คํด์ค๊ฐ ๋ค์ด๊ฐ ๊ฒ์ some์ด๋ผ๋ ํ์ ์ ์ถ๊ฐ์ ๋ณด๋ก ์ค์ ํ์์ ๋งํ๋ค. ์ด๊ฑธ Associoated Values(์ฐ๊ด๊ฐ)์ด๋ผ ํ๋ค.
var hello: String?
var hello: String? = "hello"
var hello: String? = nil
var hello: Optional<String> = .none
var hello: Optional<String> = .some("hello")
var hello: Optional<String> = .none
์ด๋ ๊ฒ ์ค์์น๋ฌธ์ผ๋ก ํ ๋น๋๋ ๊ฒ์ด ์ ๋ถ์ด๋ค!
Optional Unwrapping
๊ทธ๋ ๋ค๋ฉด, Optional์ ์ธ๋ํํ ๋, ์ค์ ๋ก ์ด๋ป๊ฒ ๋์ํ๋ ๊ฑธ๊น? ๋จผ์ ๊ฐ์ ์ธ๋ํ์ ๊ฒฝ์ฐ๋ฅผ ๋ณด์.
let hello: String? = "์๋
!"
print(hello!)
switch hello {
case .none // ์๋ฌ๋ฐ์ Crash
case .some(let data):
print(data)
}
์๋ฌด๋๋ swift์์๋ enum๊ณผ switch ๋ฌธ์ ๋ง์ด ์ฌ์ฉํ๋ค๋ณด๋, ์ด๋ ๊ฒ ์ ์ด๋ณด์๋ค. ๊ฒฐ๊ตญ ์ต์ ๋์ ์ธ๋ํํ๋ค๋ ๊ฒ์ switch๋ฌธ์ ํตํด ํ์ด์ฃผ๋ ํ์๋ฅผ ๋งํ๋ค. ์ด๋ฒ์๋ ์ต์ ๋ ๋ฐ์ธ๋ฉ์ ๋ณด์.
let hello: Optional<String> = "์๋
!"
if let hello = hello {
print(hello)
}
switch hello {
case .some(let data):
print(hello)
case .none:
// ์๋ฌด์ผ๋ ์ํจ
}
none๊ณผ some์ ์์น๊ฐ ๋ณ๊ฒฝ๋์๋ค. ์ด๋ฒ์๋ ์์์ ์ผ๋ก ํ์ด์ง ์ต์ ๋์ ๋ณด์.
var hello: String!
hello = "์๋
!"
print(hello)
var hello: Optional<String> = .none //์๋ฌด ์ด๊ธฐ์ธ์๊ฐ ์์ด ์์ฑ๋์์ ๊ฒฝ์ฐ ์ด๊ธฐ๊ฐ์ .none์ด๋ค. ?Optional๋ ๋น์ฐํ ๊ฐ์ enum์ด๊ธฐ ๋๋ฌธ์ ๊ฐ๋ค.
switch hello { // ๋ค๋ง ์ต์
๋ ๋ฐ์ธ๋ฉ์ด๋ ๊ฐ์ ์ธ๋ํ์ ํด์ฃผ์ง ์์๋ switch๋ฌธ์ ์คํํ๋ค.
case .none // ์๋ฌ๋ฐ์ Crash
case .some(let data):
print(data)
}
์์์ ์ต์ ๋์ ๊ฒฝ์ฐ, ์ต์ ๋ ์ธ๋ํ์ ํด์ฃผ์ง ์์ ์ํ์์๋ ์ฐ์ฐ์ด ๊ฐ๋ฅํ๋ค ํ๋ค. ์ด ์ด์ ๋ ๋ค๋ฅธ ๊ฒ์ด ์๋๊ณ , ์์์ ์ต์ ๋๋ก ์ ์ธ๋ ๋ณ์์ ๋ํด ์คํํ ๋, ์ปดํ์ผ๋ฌ๊ฐ ์์์ ํด๋น ์ค์์น๋ฌธ์ ๋ง๋ค์ด์ฃผ๊ธฐ ๋๋ฌธ์ด๋ค.
๊ฒฐ๊ตญ enum์ ๊ธฐ์ค์ผ๋ก ๊ฐ์ ๋๋ ์ฃผ๋ ๊ฒ์ด Optional์ ๋ณธ์ง์ด๋ค.
Nil-Coalescing Operator (Optional Defaulting)
๋ฌธ๋ฒ ์ค์, ์ต์
๋์ธ ๊ฒฝ์ฐ ํด๋น ๋ณ์๋ฅผ ์ฌ์ฉํ ๋, ๋ง์ฝ nil
์ธ ๊ฒฝ์ฐ default๊ฐ์ ๋ฐฐ์ ํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์์๋ค. ??
์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด์๋๋ฐ, ์ด์ ์ ์ฒด๋ฅผ ์์์ผ๋ ์ด ๊ตฌ๋ฌธ์ด ์ด๋ป๊ฒ ๋ณ๊ฒฝ๋๋์ง ์์๋ณด์.
let x: String? = "๋น๊ฐ ๋ง์ด์"
let y = x ?? "์ฅ๋ง ๋๋ฌ๋"
if let x = x {
y = x
} else {
y = "์ฅ๋ง ๋๋ฌ๋"
}
switch x {
case .none: y = "์ฅ๋ง ๋๋ฌ๋"
case .some(let data): y = data
}
์ด์ ๊ฐ์ด ๋์ํ๋ ๊ฒ์ด๋ค. ์ ์ฒด๋ฅผ ์๋ ์๊ฐ๋ณด๋ค ์ญ์ ๋ณ๊ฒ ์๋ค.
Optional chaining
์ ์ด๋ ๊ฒ Optional์ ๋ณธ์ง์ ์์๋ค๋ฉด, ์ฌ๋ฌ๊ฐ์ Optional ์ฒด์ด๋์ด ์ด๋ป๊ฒ ์ผ์ด๋๋์ง ์์๋ณด์.
let x: String? = "๋๋ฌด ๋์"
let y = x?.foo()?.bar?.z
switch x {
case .none: y = nil
case .some(let data1):
switch data1.foo() {
case .none: y = nil
case .some(let data2) {
switch data2.bar {
case .none: y = nil
case .some(let data3): y = data3.z
}
}
}
}
์๋ฌ์ฝ๋ผ ๋์ํ๋ค! ๊ทธ๋์ ์ด์ ๊ธ์์ ๊ณต๋ถํ์ ๋, ์๋ถ๋ถ์์ nil์ด ๋์ค๋ ๊ฒฝ์ฐ ํด๋น ๊ตฌ๋ฌธ์์ฒด๊ฐ ์คํ์ด ๋์ง ์๊ณ ๋์ด๊ฐ๋ ๊ฒ.
Optional Binding์์ ,์ &&
๋๋ฌด ์ข์ ๊ธ์ด ์์ด ๋งํฌ๋ก ๋์ฒดํ๊ฒ ๋ค!
ํต์ฌ์ &&์ ๋๊ฐ์ boolean ํํ์ ๋ฐ๋ ๋
ผ๋ฆฌ ์ฐ์ฐ์์ด๊ณ , ,
๋ ์กฐ๊ฑด์ ์ด์ด๋ถ์ด๋ ์ฉ๋๋ก ์ฌ์ฉํ๋ค๋ ๊ฒ!