본문 바로가기

iOS 프로그래밍

iOS 프로그래밍_13주차

클로저(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