스위프트의 함수 메서드 클로저
먼저 함수와 메서드에 대해서 정리하면 함수는 특정 작업을 수행하기 위해 호출할 수 있게 이름 붙여진 코드 블록이다 메서드란 특정 클래스나 구조체 또는 열거형과 연관된 함수이다 함수와 메서드는 비슷한 역할을 한다
함수
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
{ (매개변수) -> 반환형 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 클로저를 호출하여 데이터를 전달한다