🌿 옵셔널 체이닝 (Optional Chaining)
✅ 옵셔널이 뭐예요?
Swift에서 옵셔널(Optional)은 값이 "있을 수도 있고 없을 수도 있는" 상태를 표현하는 타입이에요.
var name: String? = "Alice" // 값이 있을 수도 있고
name = nil // 없을 수도 있어요!
옵셔널이 없다면 Swift는 nil 값을 허용하지 않기 때문에 반드시 초기화하거나 강제로 언래핑해야 해요. 그래서 옵셔널은 매우 중요하고 자주 사용돼요.
🔗 옵셔널 체이닝이란?
옵셔널 체이닝은 옵셔널 값에 속성, 메서드, 서브스크립트 등을 연결할 때 사용하는 문법이에요.
옵셔널이 nil이면 아무 작업도 하지 않고 nil을 반환해요. 앱이 크래시 나지 않도록 보호해줘요.
🧪 기본 문법
let result = optionalValue?.property?.method()
📘 예제: 이름이 있는 강아지 🐶
class Dog {
var name: String = "코코"
}
class Person {
var dog: Dog?
}
let person = Person()
// dog는 아직 nil이기 때문에 name에 접근 불가
let dogName = person.dog?.name
print(dogName) // nil
옵셔널 체이닝 덕분에 person.dog
가 nil이어도 앱이 멈추지 않고 안전하게 동작해요.
📦 예제 2: 깊은 객체 탐색
class Address {
var city: String = "서울"
}
class Profile {
var address: Address?
}
class User {
var profile: Profile?
}
let user = User()
let city = user.profile?.address?.city // nil
체이닝 중 하나라도 nil이면 전체 결과는 nil이 돼요.
🧠 실무 활용 예시
- JSON 디코딩 후 모델 탐색 시 유용
- API 응답으로 받은 데이터에 접근할 때 많이 사용
let region = response?.data?.user?.profile?.region
⚠️ 주의사항
- 옵셔널 체이닝의 결과는 항상 옵셔널입니다.
- nil이 아니더라도 강제로 언래핑하거나, 옵셔널 바인딩이 필요할 수 있어요.
if let dogName = person.dog?.name {
print("강아지 이름은 \(dogName)입니다")
}
🧯 Error Handling (에러 처리)
❓ 왜 에러 처리가 필요할까요?
네트워크 요청, 파일 읽기, 데이터 파싱 등 다양한 작업에서 문제가 생길 수 있어요. 이런 에러를 처리하지 않으면 앱이 충돌할 수 있어요.
Swift는 강력한 에러 처리 메커니즘을 제공합니다.
🔨 기본 문법: try-catch
enum CustomError: Error {
case invalidInput
}
func doSomething(input: Int) throws {
if input < 0 {
throw CustomError.invalidInput
}
print("입력값: \(input)")
}
do {
try doSomething(input: -1)
} catch {
print("에러 발생: \(error)")
}
😎 try? 와 try!
문법 | 설명 | 예시 |
---|---|---|
try? | 에러 발생 시 nil 반환 | let value = try? someFunc() |
try! | 에러 발생 시 크래시 | let value = try! someFunc() ❌ 위험 |
📘 예제: 파일 읽기
enum FileError: Error {
case notFound
case unreadable
}
func readFile(name: String) throws -> String {
if name != "data.txt" {
throw FileError.notFound
}
return "파일 내용입니다"
}
do {
let content = try readFile(name: "wrong.txt")
print(content)
} catch FileError.notFound {
print("파일을 찾을 수 없습니다.")
}
🧠 실무 활용 예시
- 서버 응답 오류 처리
- 디코딩 실패 시 사용자에게 경고
- 파일 또는 이미지 로딩 실패 시 대체 처리
🧬 Generic (제네릭)
🎲 제네릭이란?
다양한 타입을 하나의 함수나 타입에서 처리할 수 있게 해주는 기능이에요.
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temp = a
a = b
b = temp
}
var a = 3
var b = 5
swapTwoValues(&a, &b)
이 함수는 Int, String, Double 등 어떤 타입이든 쓸 수 있어요!
📦 예제: 스택
struct Stack<T> {
var items: [T] = []
mutating func push(_ item: T) {
items.append(item)
}
mutating func pop() -> T? {
return items.popLast()
}
}
var stringStack = Stack<String>()
stringStack.push("A")
stringStack.push("B")
print(stringStack.pop()!) // B
🎯 타입 제약 사용하기
func findIndex<T: Equatable>(of value: T, in array: [T]) -> Int? {
for (index, item) in array.enumerated() {
if item == value {
return index
}
}
return nil
}
🧠 실무 예시
- 네트워크 레이어에서 API 응답 제네릭 처리
- Custom Result 타입 만들기
- 다양한 타입에 대응 가능한 유틸리티 함수 제작
📚 Array (배열)
🔤 배열이란?
동일한 타입의 값을 순서대로 저장하는 컬렉션입니다.
var numbers = [1, 2, 3, 4, 5]
🔧 배열 메서드 모음
numbers.append(6) // [1, 2, 3, 4, 5, 6]
numbers.insert(0, at: 0) // [0, 1, 2, 3, 4, 5, 6]
let removed = numbers.remove(at: 1) // 1 제거
print(numbers) // [0, 2, 3, 4, 5, 6]
🔍 고급 기능 예시
let scores = [90, 70, 50, 100]
let passed = scores.filter { $0 >= 70 } // [90, 70, 100]
let doubled = scores.map { $0 * 2 } // [180, 140, 100, 200]
let sum = scores.reduce(0, +) // 310
🧠 실무 예시
- 테이블 뷰 데이터 관리
- 검색 결과 리스트 저장
- JSON 배열 응답 처리
⚠️ 주의사항
인덱스 접근 시 범위 초과 방지!
let value = numbers[10] // ❌ index out of range
빈 배열일 경우
.first
,.last
는 nil 반환let first = [].first // nil
✅ 마무리 요약
개념 | 핵심 요약 |
---|---|
옵셔널 체이닝 | nil 값에도 안전하게 접근하는 문법 |
에러 처리 | 예외 발생 시 안전한 대응을 위한 시스템 |
제네릭 | 여러 타입을 하나의 코드로 처리할 수 있게 함 |
배열 | 가장 기본적인 컬렉션 자료형으로 데이터 저장 및 탐색 |
'iOS 프로그래밍 실무' 카테고리의 다른 글
iOS 개발자를 위한 필수 UI 요소 및 화면 전환 완전 정리 (0) | 2025.05.22 |
---|---|
iOS UI 구축 방법 완전 정복 (1) | 2025.05.15 |
iOS 프로그래밍 실무 5주차 (0) | 2025.04.03 |
iOS 프로그래밍 실무 4주차 (0) | 2025.03.27 |
iOS 프로그래밍 실무 3주차 (0) | 2025.03.20 |