클로저(Closure)는 함수형 프로그래밍에서 중요한 개념으로, 함수가 자신이 선언된 환경(변수들)을 기억하고 사용할 수 있게 해주는 기능입니다. 즉, 함수가 정의될 때의 "상태"를 캡슐화하여, 그 함수가 호출될 때 그 상태에 접근할 수 있게 되는 것이죠.
클로저를 지원하는 언어는 대부분 함수형 프로그래밍 패러다임을 지원하는 언어들입니다. 주요 언어들을 예로 들어보겠습니다.
1. JavaScript
- JavaScript는 클로저를 지원하는 가장 유명한 언어 중 하나입니다.
- 자바스크립트에서 함수는 자신이 선언될 때의 환경을 기억합니다.
function outer() {
let counter = 0;
return function inner() {
counter++;
console.log(counter);
}
}
const closureExample = outer();
closureExample(); // 1
closureExample(); // 2
2. Python
- Python 역시 클로저를 지원합니다. 함수 내부에서 정의된 다른 함수가 바깥 함수의 변수를 사용할 수 있게 해줍니다.
def outer():
counter = 0
def inner():
nonlocal counter
counter += 1
print(counter)
return inner
closure_example = outer()
closure_example() # 1
closure_example() # 2
3. Lisp (특히 Common Lisp, Scheme)
- Lisp 계열 언어들은 함수가 1급 객체로 취급되기 때문에 클로저를 자연스럽게 지원합니다.
(defun outer ()
(let ((counter 0))
(lambda () (incf counter) (print counter))))
(setq closure-example (outer))
(funcall closure-example) ; 1
(funcall closure-example) ; 2
4. Ruby
- Ruby는 블록, 프로시저, 람다 등 여러 형태의 함수가 클로저를 생성할 수 있습니다.
def outer
counter = 0
return lambda { counter += 1; puts counter }
end
closure_example = outer
closure_example.call # 1
closure_example.call # 2
5. Swift
- Swift에서 클로저는 매우 중요한 개념으로, 특히 비동기 프로그래밍이나 함수형 프로그래밍을 할 때 유용합니다.
func outer() -> () -> Void {
var counter = 0
let inner = {
counter += 1
print(counter)
}
return inner
}
let closureExample = outer()
closureExample() // 1
closureExample() // 2
6. Go
- Go는 클로저를 지원하며, 함수 내에서 정의된 함수를 반환하는 형태로 클로저를 사용할 수 있습니다.
package main
import "fmt"
func outer() func() {
counter := 0
return func() {
counter++
fmt.Println(counter)
}
}
func main() {
closureExample := outer()
closureExample() // 1
closureExample() // 2
}
7. Haskell
- Haskell은 순수 함수형 언어로, 클로저를 자연스럽게 지원합니다.
outer :: Int -> (Int -> Int)
outer counter = \x -> counter + x
main = do
let closureExample = outer 0
print (closureExample 1) -- 1
print (closureExample 2) -- 2
8. Clojure
- Clojure는 이름에서 알 수 있듯이, 클로저가 중요한 언어입니다. 함수형 프로그래밍에 특화된 언어로 클로저를 강력하게 지원합니다.
(defn outer []
(let [counter (atom 0)]
(fn []
(swap! counter inc)
(println @counter))))
(def closure-example (outer))
(closure-example) ;; 1
(closure-example) ;; 2
9. Scala
- Scala는 JVM 기반의 함수형 프로그래밍 언어로, 클로저를 잘 지원합니다.
def outer() = {
var counter = 0
() => {
counter += 1
println(counter)
}
}
val closureExample = outer()
closureExample() // 1
closureExample() // 2
10. Elixir
- Elixir는 함수형 프로그래밍 언어로, 클로저를 지원합니다.
defmodule Example do
def outer do
counter = 0
fn ->
counter = counter + 1
IO.puts counter
end
end
end
closure_example = Example.outer()
closure_example.() # 1
closure_example.() # 2
11. Kotlin
- Kotlin도 람다식을 사용하여 클로저를 지원합니다.
fun outer(): () -> Unit {
var counter = 0
return {
counter++
println(counter)
}
}
val closureExample = outer()
closureExample() // 1
closureExample() // 2
12. PHP
- PHP는 익명 함수(Anonymous functions)와 클로저를 지원합니다.
function outer() {
$counter = 0;
return function() use (&$counter) {
$counter++;
echo $counter . "\n";
};
}
$closureExample = outer();
$closureExample(); // 1
$closureExample(); // 2
요약
대부분의 현대적인 프로그래밍 언어들이 클로저를 지원합니다. 특히 JavaScript, Python, Lisp 계열, Ruby, Swift, Scala 등은 클로저의 개념을 잘 지원하고 있으며, Go, PHP, Kotlin 등도 클로저를 잘 활용할 수 있는 기능을 제공합니다.
Extraneous : 불필요한
클로저 형식으로 사용할 때는 x: y: 쓸 필요 없음
func add(x:Int, y:Int) -> Int{
return x+y
}
print(add(x: 3, y: 5))
let add1 = {(x:Int, y:Int) -> Int in
return x+y
}
print(add1(2, 3))
iOS에서 후행 클로저(trailing closure) 스타일을 많이 사용하는 함수들을 예로 들면, Swift의 클로저 문법이 자주 사용됩니다. 후행 클로저는 함수의 마지막 매개변수로 클로저를 전달할 때, 그 클로저를 함수 호출의 괄호 밖으로 "떼어" 내는 스타일을 말합니다. iOS 개발에서 자주 사용되는 함수들을 후행 클로저 스타일로 예시를 들어보겠습니다.
1. UIView Animation
- UIView 애니메이션은 후행 클로저 스타일을 많이 사용합니다. 특히 애니메이션 블록을 정의할 때 유용합니다.
UIView.animate(withDuration: 1.0) {
view.alpha = 0.5
view.transform = CGAffineTransform(scaleX: 2.0, y: 2.0)
}
- withDuration: 메서드는 애니메이션의 지속 시간을 지정하고, 후행 클로저로 애니메이션의 동작을 정의합니다.
2. UITableView / UICollectionView
- 테이블 뷰와 컬렉션 뷰에서의 reloadData()와 같은 메서드에서는 종종 후행 클로저를 사용합니다. 특히 셀 추가나 수정, 삭제 등의 작업에서 많이 사용됩니다.
예: performBatchUpdates
collectionView.performBatchUpdates({
collectionView.insertItems(at: [indexPath])
}, completion: nil)
- performBatchUpdates 메서드는 클로저 안에서 여러 업데이트를 한 번에 실행할 수 있습니다.
3. DispatchQueue (비동기 작업)
- 비동기 작업을 처리할 때, 후행 클로저를 많이 사용합니다. DispatchQueue에서 비동기적으로 작업을 처리할 때 후행 클로저를 사용하면 코드가 더욱 간결해집니다.
DispatchQueue.main.async {
// UI 업데이트
label.text = "Updated"
}
- async 메서드에 후행 클로저로 실행할 작업을 전달합니다.
4. Text Field Delegate
- UITextField와 같은 입력 요소에서 shouldChangeCharactersIn 또는 didEndEditing과 같은 메서드는 후행 클로저 스타일로 사용되는 경우가 많습니다.
textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
- 여기서는 클로저보다는 메서드가 호출되지만, 실제로 클로저 스타일로 코드를 정의하는 경우도 많습니다.
textField.addAction(for: .editingChanged) { [weak self] textField in
self?.handleTextFieldChange(textField)
}
5. UIAlertController
- UIAlertController에서 버튼을 눌렀을 때의 액션을 처리할 때 후행 클로저 스타일을 사용할 수 있습니다.
let alertController = UIAlertController(title: "Alert", message: "Message", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .default) { _ in
print("OK Button Tapped")
})
present(alertController, animated: true)
6. NotificationCenter
- NotificationCenter에서 addObserver 메서드를 사용할 때 후행 클로저를 사용하는 경우가 많습니다.
NotificationCenter.default.addObserver(forName: .UIApplicationDidEnterBackground, object: nil, queue: .main) { notification in
print("App entered background")
}
7. GCD (Grand Central Dispatch) - asyncAfter
- asyncAfter(deadline:) 메서드는 후행 클로저 스타일을 자주 사용합니다.
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
print("This will run after 2 seconds")
}
8. NavigationController의 pushViewController
- 네비게이션 컨트롤러에서 pushViewController를 사용할 때, 보통 후행 클로저를 사용하여 애니메이션 등의 동작을 간결하게 정의할 수 있습니다.
navigationController?.pushViewController(viewController, animated: true)
9. MapView (MKMapView)
- 지도와 관련된 작업에서 후행 클로저를 사용합니다. 예를 들어, 마커를 추가하거나, 위치를 설정하는 등의 작업입니다.
mapView.addAnnotation(annotation)
mapView.setRegion(region, animated: true)
클로저 사용은 적지만, 지도 뷰에서는 보통 콜백 처리나 이벤트 핸들링을 할 때 클로저가 사용됩니다.
10. Core Data (fetch)
- Core Data에서 데이터를 비동기적으로 가져올 때 후행 클로저를 자주 사용합니다.
let fetchRequest: NSFetchRequest<Entity> = Entity.fetchRequest()
context.perform {
do {
let results = try context.fetch(fetchRequest)
print(results)
} catch {
print("Fetch failed")
}
}
11. Combine Framework (Publisher / Subscriber)
- Combine을 사용할 때, sink나 map 등과 같은 메서드에 후행 클로저를 사용하는 경우가 많습니다.
myPublisher.sink { value in
print("Received value: \(value)")
}
.store(in: &cancellables)
12. Core Animation (CABasicAnimation)
- 애니메이션을 설정할 때 후행 클로저 스타일로 속성을 설정하는 경우가 많습니다.
let animation = CABasicAnimation(keyPath: "opacity")
animation.fromValue = 1
animation.toValue = 0
animation.duration = 2.0
view.layer.add(animation, forKey: "fade")
후행 클로저 스타일을 사용하는 이유
후행 클로저 스타일은 코드의 가독성을 높이고, 클로저가 마지막 매개변수로 사용될 때 괄호 밖으로 클로저를 빼낼 수 있어 코드가 더 직관적이고 간결해집니다. 특히, 애니메이션, 비동기 작업, 콜백 등을 처리할 때 매우 유용하며, iOS에서 자주 사용됩니다.
'iOS 프로그래밍' 카테고리의 다른 글
[25.05.14_11주차] iOS 프로그래밍 실무 (0) | 2025.05.14 |
---|---|
iOS 프로그래밍_11주차 (0) | 2024.11.27 |
iOS 프로그래밍_10주차 (0) | 2024.11.20 |
iOS 프로그래밍_9주차 (0) | 2024.11.13 |
iOS 프로그래밍_8주차 (0) | 2024.11.06 |