이 포스트는 한성현 교수님의 iOS 프로그래밍 실무 수업을 듣고 작성하였습니다.
오늘은 옵셔널 체이닝에 대해 먼저 예시를 들어 알아 보며, 작성을 시작해 보겠습니다.
✔️ 옵셔널 체이닝
JavaScript에서 객체나 배열의 특정 속성 또는 메서드에 접근할 때, 해당 값이 `null` 또는 `undefined`인지 확인하지 않고도 안전하게 접근할 수 있도록 도와주는 문법입니다. 옵셔널 체이닝 연산자는 `?.`로 표시됩니다.
쉽게 설명해 보자면, "만약 이 값이 존재하면 그 다음 속성에 접근하고,
그렇지 않으면 에러를 내지 않고 `undefined`를 반환해!“라는 역할을 합니다.
이제 Swift 옵셔널 개념 실습 코드를 간단히 올리며, 설명해 보겠습니다.
일단 옵셔널은 값이 있을 수도 없을 수도 있는 타입입니다.
// 옵셔널 문자열 선언
var x: String? = "Hi" // "Hi"를 지운 후 nil 테스트도 가능
// print: 옵셔널과 강제 언래핑된 값 출력
print(x, x!) // x는 Optional("Hi"), x!는 "Hi"
// 옵셔널 바인딩 (안전하게 꺼내기)
if let a = x {
print(a) // "Hi"
}
// 강제 언래핑 후 문자열 길이 확인
let b = x!.count
print(type(of: b), b) // Int 2
// 옵셔널 체이닝을 통한 문자열 길이 접근
let b1 = x?.count
print(type(of: b1), b1!, b1!) // Optional<Int> 2 2
// nil 병합 연산자 사용 (옵셔널 x가 nil이면 "" 반환)
let c = x ?? ""
print(c) // "Hi"
x! 나 b1! 처럼 강제 언래핑은 값이 nil 일 경우 앱이 죽을 수도 있으니, 옵셔널 바인딩 기능을 사용해 주는 것이 더 좋습니다.
가급적이면, if let 이나 guard let, ??, ?. 을 사용하여 안전하게 처리하는 것이 좋은 방법이 될 것 같습니다!
✔️ 옵셔널에서 ? 와 ! 의 차이
기호 | 의미 | 위험도 | 사용 예시 |
? | 옵셔널 체이닝 | 안전함 | x?.count |
! | 강제 언래핑 | 위험함 | x! or x!.count |
📌 ?: 옵셔널 체이닝
값이 존재하면 이어서 실행하고, 값이 없으면(nil) 아무 일도 안 하고 nil 반환합니다.
var x: String? = "Hi"
let length = x?.count // Optional(2)
print(length) // Optional(2)
만약 x가 nil이면 length도 nil이 되며, 크래시 없이 안전하게 실행됩니다.
💡 사용 시기: 값이 있을 수도 없을 수도 있는 상황에서 안전하게 접근할 때.
📌 !: 강제 언래핑
옵셔널 값은 무조건 꺼내서 사용합니다.
값이 없으면(nil) 앱이 터집니다. ㅠㅠ
var x: String? = "Hi"
print(x!) // "Hi"
⚠️ 사용 시기: “여기선 무조건 값이 있어!“라고 확신할 때만 사용해야 합니다.
var x: String? = "Swift"
// 옵셔널 체이닝 (안전)
let safeCount = x?.count
print(safeCount) // Optional(5)
// 강제 언래핑 (확신이 있을 때만!)
let forcedCount = x!.count
print(forcedCount) // 5
// x가 nil일 경우
x = nil
print(x?.count) // nil (안전)
print(x!.count) // ❌ 크래시!
?는 “혹시 몰라 조심스럽게”,
!는 “무조건 있어, 질러!” 입니다.
Swift에서는 앱의 안정성이 중요하므로, !보다는
?, if let, guard let, ?? 등을 적극 활용하는 습관을 들이는 것이 좋습니다!
상황 | 추천 방식 |
값이 있을 수도 없을 수도 있다. | ? (옵셔널 체이닝) |
값이 있어야 하고, 확신이 있어야 한다. | ! (강제 언래핑) |
값이 있으면 사용, 없으면 대체 값 사용 | ?? (nil 병합 연산자) |
✔️ 오류 처리 Error Handling
✔️ throwing function
iOS 에서 가장 많이 사용되는 throwing function 을 포스팅해 보겠습니다.
🥇 1. Data(contentsOf:)
let data = try Data(contentsOf: url)
- 로컬 파일 또는 원격 URL에서 데이터 불러올 때 사용
- 오류 발생: 파일 없음, 인터넷 오류 등
🥈 2. JSONDecoder().decode(_:from:)
let user = try JSONDecoder().decode(User.self, from: data)
- JSON 데이터를 Swift 모델로 디코딩할 때
- 오류 발생: 타입 불일치, JSON 오류 등
정도 ChatGPT 를 통해 알아 보았습니다.
🥉 3. do-try-catch
이건 Swift에서 오류를 안전하게 처리하는 공식적인 방법입니다.
Swift는 오류가 발생할 수 있는 상황을 명시적으로 처리합니다. 그 중심에는 do-try-catch 문법이 있죠.
✅ 왜 필요한가요?
do {
let result = try throwingFunction()
// 성공 시 실행할 코드
} catch {
// 오류 발생 시 실행할 코드
print("오류 발생: \(error)")
}
Swift 함수 중 일부는 오류 발생 가능성이 있기 때문에 throws 키워드를 사용합니다.
이런 함수는 try 키워드와 함께 사용해야 하며, 오류를 직접 처리하거나 전달해야 합니다.
✔️ Generic
제네릭이란 코드에서 타입을 유연하게 지정할 수 있는 문법입니다. <> 이렇게 표기할 수 있습니다.
💡 왜 필요한가요?
같은 로직인데 타입만 다른 경우, 코드 중복 없이 하나의 함수나 타입으로 처리할 수 있습니다.
func swapInts(_ a: inout Int, _ b: inout Int) { ... }
func swapStrings(_ a: inout String, _ b: inout String) { ... }
이와 같은 중복되는 코드가 존재할 시에, 제네릭을 사용하게 된다면 밑과 같이 수정할 수 있습니다.
func swapValues<T>(_ a: inout T, _ b: inout T) {
let temp = a
a = b
b = temp
}
- 여기서 <T>는 타입을 추상화한 이름
- T는 호출될 때 자동으로 타입이 결정됨
✔️ Collection Type - Array
Swift에서 가장 많이 사용되는 컬렉션 타입 중 하나는 바로 Array입니다. 동일한 타입의 값들을 순서대로 저장할 수 있는 자료구조죠.
Array는 여러 값을 하나의 변수에 담아두고, 인덱스를 통해 쉽게 접근할 수 있는 순서가 있는 리스트입니다.
let numbers = [1, 2, 3, 4, 5]
- 위 배열은 Int 타입의 값을 5개 저장하고 있습니다.
- Swift의 Array는 **타입 안정성(Type-safe)**을 보장합니다.
// 타입 추론
let names = ["채림", "재현", "맥스"]
// 명시적 타입 선언
let scores: [Int] = [90, 85, 100]
// 빈 배열 만들기
var emptyArray1: [String] = []
var emptyArray2 = [String]()
이런 식으로 선언할 수 있습니다.
밑과 같은 코드로 배열 요소에 접근이 가능합니다.
let fruits = ["🍎", "🍌", "🍓"]
print(fruits[0]) // 🍎
print(fruits[1]) // 🍌
- 인덱스는 0부터 시작합니다.
- 존재하지 않는 인덱스에 접근하면 런타임 오류 발생!
즉, Array는 Swift에서 가장 자주 쓰는 기본 콜렉션! 타입 안전하고, 기능이 풍부하며, 고차 함수까지 완비한 현대적 자료구조입니다.
이전 발행글에 Array 를 다뤄 놓은 포스트도 있으니, 참고용으로 좋을 것 같습니다.
빈 배열을 받는 방법에 대해서도 설명해 보겠습니다.
두 가지로 나누어 볼 수 있습니다.
먼저, 타입을 명확히 아는 경우입니다.
var emptyArray: [Int] = []
- Int 타입의 빈 배열입니다.
- 초기화하면서 동시에 타입도 명시해주는 깔끔한 방식입니다.
두 번째로는 타입 추론이 가능한 경우입니다. 이는 보통 함수 내부나 context 가 명확할 때입니다.
var emptyArray = [String]()
- Swift가 []의 타입을 추론할 수 있도록 생성자 형태로 작성합니다.
주의 사항으로는 상수 배열은 수정이 불가하다는 점입니다.
let constantArray: [String] = []
// constantArray.append("채림") // ❌ 에러 발생!
let은 상수이기 때문에, 생성 이후에 값을 추가하거나 삭제할 수 없습니다.
빈 배열에 값을 추가하고 싶다면 항상 변수 var 로 사용해야겠지요?
'iOS' 카테고리의 다른 글
[iOS] 클래스 열거형 구조체 (0) | 2025.04.16 |
---|---|
[iOS] Table View (0) | 2025.04.02 |
[iOS] 함수와 클래스 및 상속 (0) | 2025.03.26 |
[iOS] 무드등 앱 개발 및 Swift 문법 복습 2 (0) | 2025.03.19 |
[iOS] Swift 문법 복습 (0) | 2025.03.18 |