클로저는 기능을 캡슐화한 코드 블록으로, 다음과 같은 특징을 가집니다:
{ (매개변수) -> 반환타입 in
실행 코드
}
let greet = { (name: String) -> String in
return "Hello, \(name)!"
}
print(greet("Alice")) // 출력: Hello, Alice!
func performAction(action: () -> Void) {
action()
}
performAction {
print("Action performed!") // 출력: Action performed!
}
클로저는 자신이 정의된 외부의 변수나 상수를 캡처하여 내부에서 사용 가능하며, 수정도 가능합니다.
var number = 10
let closure = { number += 5 }
closure()
print(number) // 출력: 15
map 함수에 전달된 클로저는 축약형 문법을 사용하여 $0으로 첫 번째 매개변수를 나타냅니다.
in 키워드와 타입 선언 없이도 간결하게 클로저를 작성할 수 있습니다.
let numbers = [1, 2, 3]
let doubled = numbers.map { $0 * 2 }
print(doubled) // [2, 4, 6]
@escaping 키워드를 사용하면, 클로저가 함수 실행이 끝난 뒤에도 저장되어 나중에 실행될 수 있습니다.
이 예제에서는 store 함수 내에서 받은 클로저를 외부 변수 saved에 저장하고, 나중에 실행합니다.
var saved: (() -> Void)?
func store(_ closure: @escaping () -> Void) {
saved = closure
}
store {
print("Run later")
}
saved?() // 출력: Run later
클로저 내부에서 self를 참조할 때 강한 순환 참조(Retain Cycle) 를 방지하기 위해 [weak self]를 사용합니다.
이렇게 하면 클로저는 self를 약한 참조로 가지고 있어 메모리 누수를 방지할 수 있습니다.
class Person {
var name = "John"
func greet() {
DispatchQueue.main.async { [weak self] in
print("Hello, \(self?.name ?? "Someone")")
}
}
}
@autoclosureassert(), fatalError(), guard 문 등에서 자주 사용됩니다.func log(_ message: @autoclosure () -> String) {
print("Log: \(message())")
}
log("Something happened") // 출력: Log: Something happened
lazy 프로퍼티는 지연 초기화되며, 보통 클로저로 초기화합니다.struct Example {
lazy var greeting: String = {
return "Hello, Lazy World"
}()
}
SwiftUI와 같은 DSL은 @resultBuilder로 구성됩니다.@resultBuilder
struct StringBuilder {
static func buildBlock(_ components: String...) -> String {
components.joined(separator: " ")
}
}
func greet(@StringBuilder _ content: () -> String) -> String {
return content()
}
let message = greet {
"Hello,"
"Swift"
"World!"
}
print(message) // 출력: Hello, Swift World!
| 개념 | 설명 |
|---|---|
| 기본 클로저 | 이름 없는 함수 블록 |
| 축약형 표현식 | in, $0 등을 생략하여 간결하게 작성 |
| 트레일링 클로저 | 함수 마지막 인자를 괄호 밖으로 뺌 |
| 캡처 | 외부 변수의 값을 클로저 내부에서 참조/수정 가능 |
| escaping | 클로저가 함수 실행 이후에도 실행되도록 저장됨 |
| capture list | [weak self] 등 참조 방식 명시 |
| @autoclosure | 표현식을 자동으로 클로저로 감쌈 |
| lazy | 클로저로 초기화되는 지연 프로퍼티 |
| resultBuilder | Swift DSL 구성 방식 (예: SwiftUI) |
객체지향 프로그래밍(Object-Oriented Programming)은 객체(Object) 를 중심으로 설계하는 프로그래밍 방식입니다.
| 원칙 | 설명 |
|---|---|
| 캡슐화 (Encapsulation) | 내부 구현을 숨기고 외부에는 필요한 인터페이스만 제공 |
| 상속 (Inheritance) | 기존 클래스를 확장해 새로운 클래스를 생성 |
| 다형성 (Polymorphism) | 같은 메서드가 상황에 따라 다르게 동작 |
| 추상화 (Abstraction) | 불필요한 세부 정보는 숨기고 핵심만 표현 |
class Animal {
var name: String
init(name: String) {
self.name = name
}
func makeSound() {
print("Some generic sound")
}
}
class Dog: Animal {
override func makeSound() {
print("Bark!")
}
}
let dog = Dog(name: "Buddy")
dog.makeSound() // 출력: Bark!
Swift 개발을 위해 꼭 알아야 할 두 가지 핵심 개념:
두 개념을 제대로 이해하면 코드의 재사용성과 확장성이 크게 향상됩니다.