nil 값을 다루고, 앱이 충돌하지 않도록 코드를 작성할 수 있다nil 값을 가지지 못한다var name: String = "Royce"
name = nil // ❌ 오류 발생! Swift에서는 nil을 허용하지 않음
? 를 사용하여 정의한다var name: String? = nil // ✅ 옵셔널 타입이므로 nil 할당 가능
? 사용)var number: Int? = 7
Int? ➡️ "옵셔널 Int 타입" 을 의미하며, 값이 nil 이 될 수 있다Optional<Type> 사용)var number: Optional<Int> = 7
Optional<Int> ➡️ Int? 와 같은 의미Optional<T> 는 Swift의 제네릭(Generic) 열거형이며, 내부적으로 some(T) 또는 none 을 지정한다var number1: Int? = 7
var number2: Optional<Int> = 7
? 를 사용하는 축약형을 더 많이 사용한다Optional(값) 이 표시되는 이유Optional(값) 형식으로 출력한다.var optionalNumber: Int? = 7
print(optionalNumber) // 출력: Optional(7)
optionalNumber 는 Int? 타입이므로 Swift는 이를 일반 Int 값이 아니라 옵셔널(Int) 이라는 점을 명확히 하기 위해 Optional(7) 과 같이 출력한다var a: Int? = 5
var b: Int? = 3
var result = a + b // ❌ 오류 발생! (Value of optional type 'Int?' must be unwrapped)
옵셔널(Int?) 는 실제 값이 nil 일 수도 있기 때문에, Swift는 직접 연산을 허용하지 않는다Int? 는 실제 Int 값이 아닌 Optional<Int> 타입의 래퍼(wrapper) 이므로, Int 타입과 다르게 취급된다Int)으로 변환해야 한다! (느낌표)를 붙이면 강제 언래핑이 가능하다nil 이면 런타임 오류(Crash)가 발생하므로 조심해야 한다var optionalNumber: Int? = 7
print(optionalNumber!) // ✅ 7
‼️ optionalNumber 가 nil 인 경우
var optionalNumber: Int? = nil
print(optionalNumber!) // ❌ 런타임 오류 발생! (Fatal error: Unexpectedly found nil)
⚠️ 강제 언래핑은 위험하므로 가능하면 사용을 피하는 것이 좋다
nil 이 아님을 100% 보장하는 경우var alwaysHasValue: Int! = 42
print(alwaysHasValue) // ✅ 42
if 문을 이용해 nil 여부 확인 후 강제 언래핑if 문을 사용하여 nil 이 아님을 확인한 후 언래핑하면 좀 더 안전한 코드 작성이 가능하다var optionalNumber: Int? = 10
if optionalNumber != nil {
print(optionalNumber!) // ✅ 10 (안전한 강제 언래핑)
} else {
print("값이 없습니다.")
}
nil 일 경우 언래핑을 하지 않기 때문에 런타임 오류를 방지할 수 있다!)을 사용해야 하므로, 옵셔널 바인딩을 사용하는 것이 더 권장된다if let 또는 guard let 을 사용하여 안전하게 옵셔널 값을 추출한다if let 을 사용한 옵셔널 바인딩var optionalNumber: Int? = 7
if let number = optionalNumber {
print("숫자: \(number)") // ✅ "숫자: 7"
} else {
print("값이 없습니다.")
}
nil 이 아닐 때만 실행할 경우guard let 을 사용한 옵셔널 바인딩guard let 은 함수나 특정 블록을 빠져나가야 하는 경우 유용하다func printNumber(_ number: Int?) {
guard let unwrappedNumber = number else {
print("값이 없습니다.")
return
}
print("숫자: \(unwrappedNumber)")
}
printNumber(7) // ✅ "숫자: 7"
printNumber(nil) // ✅ "값이 없습니다."
??)??)는 옵셔널 값이 nil 일 경우 기본값을 제공하는 가장 간단한 방법이다nil 일 경우 기본값을 제공해야 하는 경우와 기본적으로 값이 설정되지 않을 때 대체할 값을 사용할 때 사용한다var optionalNumber: Int? = nil
let number = optionalNumber ?? 0
print(number) // ✅ 0
?? 연산자의 사용 방법var username: String? = nil
let displayName = username ?? "Guest"
print(displayName) // ✅ "Guest"
var a: Int? = nil
var b: Int? = 5
let sum = (a ?? 0) + (b ?? 0)
print(sum) // ✅ 5
var firstName: String? = nil
var lastName: String? = "Kim"
let fullName = (firstName ?? lastName) ?? "Unknown"
print(fullName) // ✅ "Kim"
?. 연산자를 사용하여 옵셔널 값이 포함된 속성이나 메서드에 안전하게 접근하는 방법이다nil 인 경우 자동으로 nil 을 반환하고, 옵셔널 값이 존재하면 그 값의 속성이나 메서드에 접근하여 프로그램이 충돌하지 않도록 한다class Person {
var address: Address?
}
class Address {
var city: String = "Seoul"
}
let person = Person()
// 일반적인 접근 방식 (안전하지 않음)
print(person.address!.city) // ❌ 런타임 오류 발생 (Fatal error: Unexpectedly found nil)
person.address 가 nil 이므로, address!.city 를 강제 언래핑하면 런타임 오류(Crash)가 발생한다class Person {
var address: Address?
}
class Address {
var city: String = "Seoul"
}
let person = Person()
// 옵셔널 체이닝을 사용하여 안전하게 접근
print(person.address?.city) // ✅ nil (오류 없이 실행됨)
person.address 가 nil 이므로, address?.city 는 nil 을 반환하지만 오류 없이 실행된다class Person {
var address: Address?
}
class Address {
var city: String = "Seoul"
}
let person = Person()
// 옵셔널 체이닝을 사용하여 프로퍼티 접근
if let city = person.address?.city {
print("도시는 \(city)입니다.")
} else {
print("주소 정보가 없습니다.") // ✅ 출력
}
-person.address 가 nil 이면 city 도 nil 이 되므로, else 블록이 실행된다
class Person {
var address: Address?
}
class Address {
func fullAddress() -> String {
return "Seoul, South Korea"
}
}
let person = Person()
// 옵셔널 체이닝을 사용한 메서드 호출
if let address = person.address?.fullAddress() {
print(address)
} else {
print("주소 정보가 없습니다.") // ✅ 출력
}
person.address 가 nil 이므로 fullAddress() 가 실행되지 않고 nil 반환class School {
var students: [String]?
}
let school = School()
school.students = ["Alice", "Bob", "Charlie"]
// 옵셔널 체이닝을 사용한 배열 접근
if let firstStudent = school.students?.first {
print("첫 번째 학생은 \(firstStudent)입니다.")
} else {
print("학생 명단이 없습니다.") // ✅ 출력되지 않음
}
students 가 nil 이면 students?.first 도 nil 이지만, 오류 없이 실행된다class Company {
var ceo: CEO?
}
class CEO {
var name: String = "Steve Jobs"
var office: Office?
}
class Office {
var address: String = "Cupertino, California"
}
let apple = Company()
// 옵셔널 체이닝을 사용한 다중 속성 접근
if let officeAddress = apple.ceo?.office?.address {
print("회사 주소: \(officeAddress)")
} else {
print("회사 주소 정보가 없습니다.") // ✅ 출력
}
ceo가 nil이므로, ceo?.office?.address전체가 nil이 되고 else 블록이 실행된다??)를 함께 사용하면 nil일 경우 기본값을 제공할 수 있다let companyAddress = apple.ceo?.office?.address ?? "주소 정보 없음"
print(companyAddress) // ✅ "주소 정보 없음"
nil이면 "주소 정보 없음"이 기본값으로 설정된다nil이면 연산이 중단된다class User {
var profile: Profile?
}
class Profile {
var bio: String?
}
let user = User()
user.profile?.bio = "iOS Developer" // ✅ 실행되지만 아무런 효과 없음 (bio는 설정되지 않음)
profile이 nil이면 bio에 값을 설정할 없다➡️ 해결 방법: 옵셔널 바인딩(if let)을 사용하여 nil 여부를 먼저 확인
??)nil이 반환될 경우 기본값을 제공하는 것이 좋다let bio = user.profile?.bio ?? "소개 없음"
print(bio) // ✅ "소개 없음"
if let)if let bio = user.profile?.bio {
print("사용자 소개: \(bio)")
} else {
print("소개 정보가 없습니다.")
}
Swift에서는 함수가 값을 반환하지 못할 수도 있는 경우를 고려해야 한다
예를 들어:
nil 반환 가능nil 반환 가능nil 반환 가능이럴 때 함수의 반환 타입을 옵셔널로 설정하면 nil을 반환할 수 있다
nil로 설정func search(query: String, category: String? = nil) {
let selectedCategory = category ?? "전체"
print("'\(query)'을(를) \(selectedCategory)에서 검색합니다.")
}
search(query: "Swift") // ✅ "'Swift'을(를) 전체에서 검색합니다."
search(query: "iPhone", category: "전자제품") // ✅ "'iPhone'을(를) 전자제품에서 검색합니다."
nil을 전달할 수 있다func greet(name: String?) {
if let unwrappedName = name {
print("안녕하세요, \(unwrappedName)님!") // ✅ "안녕하세요, Royce님!"
} else {
print("이름이 없습니다.") // ✅ "이름이 없습니다."
}
}
greet(name: "Royce") // ✅ "안녕하세요, Royce님!"
greet(name: nil) // ✅ "이름이 없습니다."
?? 닐 병합 연산자 사용)nil일 경우 기본값을 사용하도록 설정 가능func greet(name: String?) {
let finalName = name ?? "Guest" // `nil`이면 "Guest" 사용
print("안녕하세요, \(finalName)님!")
}
greet(name: "Royce") // ✅ "안녕하세요, Royce님!"
greet(name: nil) // ✅ "안녕하세요, Guest님!"
?.을 사용하면 안전한 접근 가능class User {
var nickname: String?
}
func welcome(user: User?) {
print("환영합니다, \(user?.nickname ?? "Guest")님!")
}
let user1 = User()
user1.nickname = "Royce"
welcome(user: user1) // ✅ "환영합니다, Royce님!"
welcome(user: nil) // ✅ "환영합니다, Guest님!"
func findUser(id: Int) -> String? {
let users = [1: "Royce", 2: "Steve"]
return users[id] // 없는 ID일 경우 자동으로 `nil` 반환
}
let user = findUser(id: 1)
print(user) // ✅ Optional("Alice")
nil 반환if let userName = findUser(id: 1) {
print("사용자: \(userName)") // ✅ "사용자: Alice"
} else {
print("사용자를 찾을 수 없습니다.")
}
if let)을 사용하여 nil인지 확인 후 안전하게 사용 가능let userName = findUser(id: 3) ?? "Guest"
print("사용자: \(userName)") // ✅ "사용자: Guest"
"guest"를 기본 값으로 사용func convertToString(number: Int?) -> String {
return number?.description ?? "값 없음"
}
print(convertToString(number: 10)) // ✅ "10"
print(convertToString(number: nil)) // ✅ "값 없음"
?.)과 ??를 활용하여 nil 처리 가능func stringToInt(_ str: String) -> Int? {
return Int(str) // 변환 실패 시 `nil` 반환
}
print(stringToInt("123")) // ✅ Optional(123)
print(stringToInt("Swift")) // ✅ nil
nil 반환