Post

스위프트의 함수 메서드 클로저

스위프트의 함수 메서드 클로저

먼저 함수와 메서드에 대해서 정리하면 함수는 특정 작업을 수행하기 위해 호출할 수 있게 이름 붙여진 코드 블록이다 메서드란 특정 클래스나 구조체 또는 열거형과 연관된 함수이다 함수와 메서드는 비슷한 역할을 한다

함수

1
2
3
4
func buildMessageFor(name: String, count: Int) -> String {
    return(" \(name), you are customer number \(count) ")
}
buildMessageFor(name: "min", count: 23)

Func 함수이름(매개변수) -> 리턴 타입{ 실행 코드} 가 된다

여기서 문자열을 반환하기위해서 return을 사용했는데 단일 표현식을 가지고 있다면 return을 생략할 수 있다  

지역 매개변수명, 외부 매개변수명

위 함수에서는 지역 매개변수, 외부 매개변수명 둘다 같은 이름으로 사용한다 외부 매개변수를 함수를 사용할 때 매개변수를 지정할때 이용하고 내부 매개변수는 함수 내부에서 입력받은 매개변수를 이용할때 사용한다  

외부 매개변수 이용 x

1
2
3
4
func buildMessageFor(_ name: String, _ count: Int) -> String {
    return(" \(name), you are customer number \(count) ")
}
buildMessageFor("min", 23)

함수 선언시 매개변수 이름 앞에 언더바(_)를 사용하면 함수를 이용할때 외부 매개변수의 이름을 사용하지 않을 수 있다 하지만 순서는 맞춰야한다  

외부 매개변수 따로 선언

1
2
3
4
func buildMessageFor(user name: String, number count: Int) -> String {
    return(" \(name), you are customer number \(count) ")
}
buildMessageFor(user: "min",number: 23)

함수 선언시 외부 매개변수 이름 따로 설정  

매개변수 기본값 설정

함수 선언시 기본값을 설정

1
2
3
4
5
6
func buildMessageFor(name: String = "jin", count: Int = 22) -> String {
    return(" \(name), you are customer number \(count) ")
}
buildMessageFor(name: "min", count: 23) //: min, you are customer number 23
buildMessageFor(count: 23) //: jin, you are customer number 23
buildMessageFor() //: jin, you are customer number 22

 

결과 여러개 반환

결과값을 튜플로 래핑한다면 여러개의 결과값을 함수가 반환할 수 있다 (파이썬에서 리스트로 변환해서 결과를 여러개 반환하는 느낌)

1
2
3
4
5
6
7
8
9
10
11
func sizeConverter ( inch: Float) -> (yards: Float, centimeters: Float, meters: Float) {
    let yards = inch * 0.0277778
    let centimeters = inch * 2.54
    let meters = inch * 0.0254
    return (yards, centimeters, meters)
}

let length = sizeConverter(inch: 2.0)
length.yards //: 0.0555556
length.centimeters //: 5.08
length.meters //:0.0508

 

가변 매개변수

매개변수가 몇개 오는지 모를때 사용 가능하다

1
2
3
4
5
6
func showNumber(_ nums: Int...) {
    for num in nums{
        print(num)
    }
}
showNumber(5,4,2,3,5,2)

위 함수는 int형태의 매개변수들이 배열 형태로 들어가게 된다 주의할 점으로 가변 매개변수 뒤 추가적인 매개변수가 있다면 외부 매개변수명을 생략하면 안된다 또는 가변 매개변수를 함수 선언시 가장 마지막에 선언한다

 

함수 내부에서 매개변수 변경

내부 매개변수를 이용할 때 내부 매개변수는 상수로 이용되기 때문에 변경이 불가능하다 따라서 변수에 저장한뒤 그 값을 이용한다

 

입출력 매개변수

만약 매개변수에 변수를 넣어서 함수를 실행하고 변수값을 변경하는 함수가 있다고 하자 이 함수를 실행하기전 변수와 실행후 (넣은)변수값을 보면 변화가 없다 왜냐하면 함수 내부에서는 매개변수 값의 복사본으로 처리하기 때문이다 ->전역 변수의 의미가 아님

함수가 값을 반환한 뒤에도 매개변수에 대한 변경을 유지하려면 함수 선언부 내에서 매개변수를 입출력 매개변수로 선언해야 한다

1
2
3
4
5
6
7
var num: Int = 3
func showNumber( nums: inout Int,name:String) -> Int{
    nums += 1
    return(nums)
}
showNumber(nums: &num, name: "Asdf")
print(num)//:4

함수 선언시 타입 앞에 inout 작성 함수 호출시 매개변수에 & 사용

 

클로저

클로저는 코드 블록 또는 익명함수로 특정 작업을 수행하는 코드가 포한된 코드 단위이다 swiftdp서 클로저는 변수나 상수에 저장되거나 함수로 전달될 수 있다

클로저의 3가지 형식

  1. 전역 함수: 이름이 있고 어떤 값도 캡처하지 않는 클로저
  2. 중첩 함수: 이름이 있고 상위 함수에서 정의된 값들을 캡처할 수 있는 클로저
  3. 클로저 표현식: 간단한 문법으로 작성된 이름 없는 클로저

 

클로저의 기능

  1. 캡처기능 클로저는 주변 문맥에서 정의된 변수나 상수를 캡처하여 해당 값을 사용하거나 수정할 수 있다
  2. 참조타입 클로저는 참조 타입이기 때문에 여러 변수나 상수에 동일한 클로저를 할당하면 동일한 참조를 공유한다
  3. 간결한 문법 클로저 표현식은 타입 추론, 단축 인자 이름, 후행 클로저를 통해서 간결하게 작성된다

 

클로저 문법

1
2
3
{ (매개변수) -> 반환형 in
    실행 코드
}

함수와 유사하다 in 키워드를 사용해서 매개변수와 실행코드를 구분한다

1
2
3
4
5
6
7
// 두 숫자를 더하는 클로저
let add: (Int, Int) -> Int = { (a, b) in
    return a + b
}

let result = add(3, 5)
print(result) // 출력: 8

클로저를 함수의 매개변수로 전달

1
2
3
4
5
6
7
8
func performOperation(_ operation: (Int, Int) -> Int, a: Int, b: Int) {
    let result = operation(a, b)
    print("결과: \(result)")
}

// 클로저를 함수에 전달
performOperation({ (x, y) in x * y }, a: 3, b: 4) // 출력: 결과: 12

위 코드는 함수의 매개변수에 클로저, a, b를 받는다 그리고 클로저를 시행시키는데 그때 입력받은 매개변수 a, b를 넣어서 클로저를 수행한다

후행 클로저

1
2
3
4
// 후행 클로저 사용
performOperation(a: 3, b: 4) { (x, y) in
    return x - y
} // 출력: 결과: -1

이전에 정의한 함수에서는 매개변수 마지막이 b였지만 만약 클로저가 마지막 매개변수로 작성됐다면 위 코드처럼 클로저를 함수 호출 괄호 밖에서 작성할 수 있는 문법이다 이로써 코드의 가독성을 높이고 간결하게 표현할 수 있다

단축 인자 이름

1
2
// 단축 인자 이름 사용
performOperation(a: 6, b: 2) { $0 / $1 } // 출력: 결과: 3

단축 인자 이름을 사용해서 간단하게 표현 위 코드에서는 후행 클로저를 사용고 단축 인자를 사용해서 매우 간간하게 나눗셈 결과를 반환하도록 했다

값 캡처

1
2
3
4
5
6
7
8
9
10
11
12
func counter() -> () -> Int {
    var count = 0 // 클로저가 캡처할 변수
    return {
        count += 1 // count 값을 증가
        return count
    }
}

let myCounter = counter() // count를 캡처
print(myCounter()) // 1
print(myCounter()) // 2
print(myCounter()) // 3

c언어의 static과 유사한 느낌을 받았다

다른 예시

1
2
3
4
5
6
7
8
9
10
11
func makeMultiplier(multiplier: Int) -> (Int) -> Int {
    return { number in
        return number * multiplier
    }
}

let double = makeMultiplier(multiplier: 2) // multiplier = 2를 캡처
let triple = makeMultiplier(multiplier: 3) // multiplier = 3을 캡처

print(double(5)) // 10 (5 * 2)
print(triple(5)) // 15 (5 * 3)

캡처를 이용할때는 클로저 2개 이상을 이용하는것 같다

클로저는 이름을 가지지 않고 in을 사용한다 이름이 없는 함수다 재사용하지 않는다면 클로저로 사용하는것도 좋을것 같다

비동기 작업

1
2
3
4
5
6
7
8
9
10
11
12
13
func fetchData(completion: @escaping (String) -> Void) {
    DispatchQueue.global().async {
        // 네트워크 요청 시뮬레이션
        let data = "데이터 가져오기 완료"
        DispatchQueue.main.async {
            completion(data)
        }
    }
}

fetchData { result in
    print(result) // 출력: 데이터 가져오기 완료 그냥 출력이기 때문에 리턴없음 Void
}

fetchData에서 클로저를 매개변수로 받고 @escaping 키워드는 클로저가 함수가 종료된 뒤에 호출될 수 있음을 나타낸다 완료되면 completion 클로저를 호출하여 데이터를 전달한다

This post is licensed under CC BY 4.0 by the author.