일급 객체
일급객체, 일급함수란 객체나 함수가 값으로 취급될 수 있다는 것이다.
값으로 취급 할 수 있다는 것의 의미는 변수를 할당받거나, 파라미터로 전달되거나 리턴 값으로 취급 될 수 있다는 것이다.
설명으로만 보면 이해하기 힘든데 코드를 보면 쉽게 이해가 가능하다
// 반환 값
func getName() -> String {
"Name"
}
// 파라미터로 전달
func add(_ a: Int, _ b: Int) -> Int {
a + b
}
// 변수에 저장
struct Person {
let name: String
let age: Int
}
let person = Person(name: "준", age: 20)
위와 같이 처럼 정수형, 배열, 객체, 클래스 등 변수에 할당받을 수 있는 타입을 일급객체라고 한다.
일급함수
일급함수란 일급객체로 취급되는 함수를 일급 함수라고 한다.
즉 함수를 값처럼 다를 수 있다는 이야기. Swift에선 함수(클로저)를 일급객체로 취급한다.
// 매개변수
func run(_ completion: ((String) -> Void)?) {
completion?("Finish")
}
// 변수에 저장
func helloWorld() {
print("Hello World!")
}
let task1 = helloWorld
let task2 = {
print("Good Bye World!")
}
var tasks: [() -> Void] = [task1, task2]
// 리턴 값
func plus(_ x: Int) -> (Int) -> Int {
{ y in x + y }
}
let plus5 = plus(5)
print(plus5(10)) // 15
고차함수
고차함수는 다른 함수를 인자를 받거나 함수를 결과값으로 반환하는 함수를 말한다.
그러므로 모든 고차함수는 일급함수(일급객체)이다.
당연하게도 모든 일급함수가 고차함수인것은 아니다
- 모든 일급함수가 다른 함수를 인자로 받거나 함수를 결과값으로 반환하는게 아니기 때문
Swift에선 클로저가 일급객체 취급이므로 고차 함수는 클로저를 인자로 받거나 반환할 수 있다
고차함수의 장점
- 코드 가독성 향상
- 재사용성 증가
- 유연성 및 확장성 증가
// 코드 가독성 향상
let numbers = [1, 2, 3, 4, 5]
var evens: [Int] = []
for number in numbers {
if number % 2 == 0 {
evens.append(number)
}
}
let evens2 = numbers.filter { $0 % 2 == 0 }
// 재사용성 증가
func performCalculation(_ a: Int, _ b: Int, using operation: (Int, Int) -> Int) -> Int {
return operation(a, b)
}
let sum = performCalculation(3, 5, using: +) // 8
let product = performCalculation(3, 5, using: *) // 15
// 유연성 및 확장성 증가
// completion 구현에 따른 확장성
func reqeust(completion: (() -> Void)?) {
DispatchQueue.global().async {
completion?()
}
}
reqeust {
print("do SomeThing")
}
reqeust {
print("do SomeThing 2")
}
하지만 단점도 존재하는데 대표적인것이 콜백 지옥이다
func getUserID(_ completion: @escaping (Result<String, Error>) -> Void) {
... 비동기처리 ...
isSuccess ? completion(.success("ID")) : completion(.failure(SomeError))
}
func getUserName(id: String, _ completion: @escaping (Result<String, Error>) -> Void) {
... 비동기처리 ...
isSuccess ? completion(.success("Name")) : completion(.failure(SomeError))
}
getUserID { result in
switch result {
case .success(let id):
getUserName(id: id) { result in
switch result {
case .success(let name):
print(name)
case .failure(let error):
print(error)
}
}
case .failure(let error):
print(error)
}
}
순수함수
순수함수는 두가지 조건을 만족해야 한다
- 동일한 input엔 항상 동일한 output
- Side Effect가 없다 (함수 외부에서 변경이 일어나지 않고 함수 실행하는 것 외에 다른 외부 상호작용이 없다)
순수함수는 수학의 함수와 동일하다고 생각하면 된다
함수 f(x) = x + 5 에서 f(5)는 항상 10 이다. f(6)은 항상 11이다
func add(_ a: Int, _ b: Int) -> Int {
a + b
}
add(10, 5) // 항상 10
func minus(_ a: Int, _ b: Int) -> Int {
a - b
}
minus(10, 5) // 항상 5
// Side Effect가 존재
var multiple = 2
func increment(_ a: Int) -> Int {
a * multiple
}
increment(5) // 10
multiple = 10
increment(5) // 100
즉 Side Effect가 존재하지 않으면 동일한 input에 동일한 output이 나온다
간혹가다 아래 처럼 Date(), random() 처럼 input이 없고 동일한 함수를 호출하는데 다른 output이 나오니까
앞에 말한 조건에 위배되는것 아닌가라고 생각할 수 있는데
엄연히 사이드 이팩트가 존재하는 불순 함수들이다
// 외부 환경인 현재 시간에 의존
func getCurrentTime() -> Date {
return Date()
}
// 외부 환경인 난수 생성기에 의존
func getRandomNumber() -> Int {
return Int.random(in: 1...100)
}'iOS > Swift' 카테고리의 다른 글
| [Swift] RxSwift의 subscribe(on:)와 observe(on:), Combine의 subscribe(on:)와 receive(on:) (0) | 2025.06.20 |
|---|---|
| [Swift] @Published는 값을 언제 방출할까 ? (0) | 2025.06.20 |
| [Swift] Key Value Coding(KVC), Key Value Observing(KVO) (1) | 2024.06.15 |
| [Swift] GCD, Async/Sync 알아보기 비동기(Asynchronous)란 말과 Concurrency(동시성)란 말이 같은 말인가? (1) | 2024.01.22 |
| [Swift] RxSwift, Combine 원리 이해하기 (0) | 2024.01.20 |