2022-09-26 월요일
3주차
1교시
🦁 이 코드는 어떤 과정을 통해서 나오게 된 것이다! 하고 팀원 모두가 이해할 수 있도록 설명하는 습관을 들이도록 하자.
1/3은 내가 코드를 쓰는 시간, 1/3은 내 코드를 검토해달라고 부탁하는 시간, 1/3은 남의 코드를 검토하는 시간.
남에게 이 코드가 어떻게 읽혀질지 생각하는 시간이 필요하다. 한번에 뚝 떨어진 코드가 아니다.
그 코드를 짠 노하우를 공유하는 것이라고 볼 수 있다.
Swift
함수, 메서드, 클로저
목표
함수, 메서드, 클로저
- 앞서 배운 것
- 제어흐름 → 반복제어, 조건부 흐름
- 이번에 배울 것
- Swift의 함수, 메서드, 클로저는 체계적인 구조와 효율적인 코드를 작성하는 핵심 부분이며, 코드의 반복을 피하면서 프로그램을 구조화하는 방법을 제공한다.
- 우리는 함수, 메서드, 클로저를 선언하며 어떻게 사용하는지 살펴볼 것이다.
함수란 무엇인가
함수는 수학에서 나온 개념이긴 하다.
함수는 특정 작업을 수행하기 위해 호출할 수 있게 이름 붙여진 코드 블록이다.
다음번에도 또 쓰일 내용이면 재사용할 수 있도록 만들어보자. 한번 만들어 두면 여기저기 쓰이니까! → 함수
- 작업을 수행하기 위한 데이터가 제공될 수 있고 작업의 결과를 호출한 코드로 반환할 수도 있다.
- x라는 값을 집어넣으면 y라는 결과가 나오는 y=f(x)를 생각해보자.
- 예) Swift 프로그램에서 수행해야 할 값을 받아(매개변수-parameter) 산술식을 수행하면, 계산 결과가 반환되도록 프로그래밍할 수 있다.
- 프로그램 코드 어디서든지 산술 계산이 필요하면 매개변수의 값을 인자(argument)로 이 함수를 전달하여 호출하면 결괏값이 반환될 것이다.
매개변수(parameter)와 인자(argument)라는 용어가 서로 혼용되고는 한다. 하지만 이들에겐 미묘한 차이가 있다. (in-out)
- 함수가 호출할 때 받게 되는 값 → 매개변수 (x값)
- 하지만 실제로 함수가 호출되고 값이 전달된 시점에서는… → 인자 라고 부른다.
메서드란 무엇인가
모든 함수는 메서드이다.
본질적으로 메서드는 특정 클래스나 구조체 또는 열거형과 연관된 함수다.
예를들어, 여러분이 Swift 클래스 내에서 함수를 선언햇다면 이것은 메서드로 간주된다. (객체지향에서 다룰 예정)
- 특별한 언급이 없다면 함수에 대해 설명하는 규칙과 동작 모두가 메서드에서도 동일하게 적용된다.
그래서… 오전에는 playground로 함수와 관련된 문제를 풀었다! (feat. 브레인서바이벌)
2교시, 3교시
Playground → 코딩 배우기 1 → 새로운 동작 구성하기(함수)
와!! 진행해보자.
4교시
함수를 선언하는 방법
func 함수명(매개변수 이름: 매개변수 타임, 매개변수 이름: 매개변수 타입, ... ) -> 반환결과 타입 {
// 함수 코드
}
- 매개변수 이름: 매개변수 타임
- option
- func : 이것이 함수라고 컴파일러에게 알려주기 위해 사용되는 키워드
- func는 키워드이므로 변수명으로 쓸 수 없다.
- 함수명 : 함수에 할당되는 이름
- 앱 코드 내에서 함수를 호출할 때 참조되는 이름
- 소문자로 시작한다(일종의 약속임)
- 매개변수 이름 : 함수 코드 내에서 참조할 매개변수 이름
- 반환결과 타입 : 함수가 반환하는 결과의 데이터 타입
- 만일 함수가 결과를 반환하지 않는다면 반환 결과 타입을 지정하지 않는다.
- 함수 코드 : 작업을 수행하는 함수의 코드 (수행 결과는 return으로 보내준다)
func orderCoffee(coffeeName: String, count: Int) -> coffee {
// 함수 코드
}
- 함수 시그니처(function signature)
- 함수명(매개변수 이름: 매개변수 타입, …) → 반환결과 타입
- 스위프트 컴파일러는 이 부분만 보고 함수의 이름표라고 생각한다. 함수명만 보고 함수의 전체를 보는게 아니라 함수 시그니처를 보고 함수 덩어리로 인식한다.
매개변수를 받지않고 결과를 반환하지도 않고 메시지만 표시하는 단순한 함수의 예제이다.
func sayHello() {
print("Hello")
}
매개변수로 문자열 하나와 정수 하나를 받으며 문자열 결과를 반환하는 함수의 예제이다.
func buildMessageFor(name: String, count: Int) -> String {
return "\\(name), you are customer number \\(number)")
}
단일 표현식에서의 암묵적 반환
return의 내용이 한 줄이면 return 생략이 가능
- 만약 함수가 단일 표현식을 가지고 있다면 return 구문을 생략할 수 있다.
func buildMessageFor(name: String, count: Int) -> String {
return "\\(name), you are customer number \\(number)")
}
// 한줄이면 아래와 같이 쓸 수도 있다.
func buildMessageFor(name: String, count: Int) -> String {
"\\(name), you are customer number \\(number)")
}
- reutrn 구문은 함수가 단일 표현식을 가지고 있을 때만 생략할 수 있다
- 다음의 코드는 함수가 두 개의 표현식을 가지고 있기 때문에 컴파일 에러가 발생한다.
func buildMessageFor(name: String, count: Int) -> String {
let uppername = name.uppercased()
"\\(name), you are customer number \\(number)") // 컴파일 에러. 허용안된다구욧!!
}
함수 호출하기
함수를 선언했다면 다음과 같은 구문을 이용하여 호출하게 된다.
함수명(인자1, 인자2, ...)
- 함수를 통해 전달되는 각각의 인자는 함수가 받도록 구성된 매개변수와 일치해야 한다.
- 예) 매개변수를 받지 않고 아무런 값도 반환하지 않는 sayHello라는 이름의 함수를 호출하려면 아래와 같다.
sayHello()
반환값 처리하기
- 두 개의 매개변수를 받아 결과를 반환하는 buildMessageFor라는 이름의 함수를 호출하기 위해서는 다음과 같은 코드를 작성하게 될 것이다.
let message = buildMessageFor(name: "John", count: 180)
- 위 예제에서 message라는 이름의 새로운 변수를 생성하고 함수로부터 반환되는 결과를 저장하기 위해 할당 연산자(=)를 사용하였다.
- Swift로 개발할 때 메서드나 함수를 호출하여 반환된 결과값을 사용하지 않는 경우가 생긴다. 이럴 때는 반환값을 ‘_’에 할당하여 그 값을 버린다.
_ = buildMessageFor(name: "John", count: 180)
지역 매개변수 명과 외부 매개변수 명
앞선 예제의 함수들은 선언할 때 함수 코드 내에서 참조할 수 있는 이름을 할당한 매개변수로 구성하였다.
이렇게 선언된 매개변수를 지역 매개변수명(local parameter name)이라고 한다.
- 함수 매개변수에는 지역 매개변수명 뿐만 아니라 외부 매개변수명(external parameter name)도 있을 수 있다.
- 이들 이름은 함수가 호출될 때 참조되는 매개변수의 이름이다.
- 기본적으로, 함수 매개변수에는 동일한 지역 매개변수명과 외부 매개변수명이 할당된다.
let message: String = buildMessageFor(name: "John", count: 180)
위에서 호출한 함수의 선언부를 보면 ‘name’과 ‘count’를 지역 매개변수이자 외부 매개변수명으로 사용한다고 선언했다.
func buildMessageFor(name: String, count: Int) -> String {
return "\\(name), you are customer number \\(count)")
}
- 매개변수에 할당된 디폴트 외부 매개변수명은 다음과 같이 지역 매개변수명 앞에 밑줄 문자를 써서 없앨 수 있다.
func buildMessageFor(_ name: String, count: Int) -> String {
return "\\(name), you are customer number \\(count)")
}
let message = buildMessage("John", count: 100)
밑줄 문자를 써서 없애면 영어 문장을 읽는 것처럼 자연스럽게 읽을 수 있다.
→ build message for John.
- 다른 방법으로, 함수 선언부에서 지역 매개변수명 앞에 외부 매개변수명을 선언하면 간단하게 외부 매개변수명이 추가된다.
- 예를 들어, 다음의 예제코드는
- 첫번째 매개변수명의 외부 매개변수명을 username으로 지정한다.
- 두번째 매개변수명의 외부 매개변수명을 userCount로 지정한다.
func buildMessageFor(username name: String, userCount count: Int) -> String {
return "\\(name), you are customer number \\(count)")
}
- 이렇게 함수를 선언했다면 함수를 호출할 때 반드시 외부 매개변수명을 참조해야 한다.
let message = buildMessageFor(username: "John", userCount: 100)
함수 밖에서 부르는 이름과 안에서 부르는 이름을 다르게 만들어주는 것이다.
- 함수를 호출할 때 인자를 전달하기 위하여 외부 매개변수명이 사용됨에도 함수 내에서 매개변수를 참조할 때는 여전히 지역 매개변수명이 사용된다.
- 인자에 대한 외부 매개변수명을 사용하여 함수를 호출할 때는 함수를 선언했을 때와 동일한 순서로 인자를 넣어야 한다.
함수에 디폴트 매개변수 선언하기
기본값 설정되어 있으면 아무것도 안쓰고 함수를 호출해도 문제 없지요~
Swift는 함수가 호출될 때 인자로 쓸 값이 들어오지 않은 경우에 사용할 디폴트 매개변수 값을 지정할 수 있다.
- 이것은 함수를 선안할 때 매개변수에 디폴트 값을 할당하면 된다.
- 디폴트 매개변수를 사용하도록 함수를 선언할 때 디폴트 값을 매개변수 끝에 둔다.
- 이렇게 하여 컴파일러가 어떤 매개변수가 함수 호출 시에 생략된 건지 혼돈하지 않도록 한다.
- Swift는 함수를 호출하면 반드시 사용되는 디폴트 값을 설정한 매개변수에 대해 지역 매개변수명을 기반으로 한 디폴트 외부 매개변수명을 제공한다.
디폴트 매개변수에 대해 확인하기 위해, 인자로 고객 이름을 전달하지 않은 경우 디폴트 값인 ‘Customer’라는 문자열이 사용되도록 buildMessageFor 함수를 수정해보자.
func buildMessageFor(_ name: String = "Customer", userCount count: Int) -> String {
return "\\(name), you are customer number \\(count)")
}
// 이제 이 함수는 name 인자를 전달하지 않고 호출될 수 있다.
let message = buildMessageFor(count: 100)
print(message) // Customer, you are customer number 100
여러 결과값 반환하기
튜플 기억하세요? 그것을 응용합니다.
결과값들을 튜플로 묶어주면 여러 개의 결과값을 함수가 반환할 수 있다.
다음의 함수를 길이에 대한 인치(inch) 단위의 측정값을 매개변수로 받는다.
// 이 함수는 매개변수로 받은 값을 야드, 센티미터, 미터로 반환하고,
// 이들 값을 하나의 튜플 인스턴스에 넣어 반환한다.
func sizeConverter(_ length: Float) -> (yards: Float, centimeters, meters: Float) {
let yards = length * 0.0277778
let centimeters = length * 2.54
let meters = length * 0.0254
return (yards, centimeters, meters)
}
let lengthTupe = sizeConverter(20)
print(lengthTuple.yards)
print(lengthTuple.centimeters)
print(lengthTuple.meters)
튜플에 묶인 것도 하나의 타입이므로 설정을 잘 해줘야 한다.
가변개수 매개변수
딱히 외울 필요는 없다. 근데 어디에 쓰는지는 알아야 한다.
정리하면 매개변수가 몇개가 들어올 지 모르는데, 이것을 … 으로 표현한다.
이렇게 쓰는 것보다는 배열 자체를 받으려고 하거나, 다른 방법을 쓰지 직접 작성하는 일은 드물 것이다. 그러나 이런 코드를 보면 알아야 하니까. 무엇인지 알고는 있자.
- 앱 코드 내에서 함수가 호출될 때 함수가 받게 될 매개변수가 몇 개인지 알 수 없는 경우도 있다.
- Swift는 가변 매개변수(variadic parameter)를 사용하여 이러한 경우를 처리할 수 있게 한다.
- 함수가 지정된 데이터 타입의 매개변수 0개 또는 그 이상을 받는다는 것을 의미하는 점 세개(…)를 이용하여 가변개수 매개변수를 선언한다.
- 함수 내에서 매개변수는 배열 개체의 형태로 사용할 수 있다
- 예를 들어, 다음의 함수는 문자열 값들을 매개변수로 받아 콘솔 패널에 출력하는 함수다.
func displayStrings(_ string: String...) {
for string in strings {
print(string)
}
}
displayStrings("one", "two", "three", "four")
변수인 매개변수
- 함수가 받는 모든 매개변수는 기본적으로 상수로 취급된다.
- 즉, 함수의 코드 내에서 매개변수의 값이 변경되는 것을 막는다.
- 만약 함수 내에서 매개변수의 값을 변경하고 싶다면, 매개변수의 **섀도우 복사본(shadow copy)**을 반드시 생성해야 한다.
- 다음의 함수는 인치 단위의 길이와 너비를 매개변수로 전달받아 두 값에 대한 섀도우 변수를 생성하고 각각의 값을 센티미터로 변환한 후에 면적을 계산하여 반환한다.
func calcurateArea(length: Float, width: Float) -> Float {
var length = length
var width = width
length = length * 2.54
width = width * 2.54
return length * width
}
print(calcurateArea(length: 10, width: 20))
🦁 문법으로 허용된다고 해서 모두 쓸 수 있지만, 회사나 조직 내부에서 따로 정해진 문법만 쓰는 경우도 있다. 코딩 스타일을 규격화하기 위해서!! 회사, 조직마다 코딩 스타일이 있고 어디가 더 좋다 이런건 없다.
입출력 매개변수로 작업하기
- 어떤 변수가 매개변수로 함수에 전달되면 그 매개변수는 해당 함수 내에서 상수로 취급된다는 것을 배웠다.
- 또한 매개변수의 값을 변경하고 싶을 때는 섀도우 복사본을 생성해야 한다는 것을 배웠다.
- 이것은 복사본이기 때문에 어떻게 변경한다고 해도 기본적으로 원본 변수에 반영되지 않는다.
var myValue = 10
func doubleValue(_ value: Int) -> Int {
var value = value
value += value
return value
}
print("Before functino call myValue = \\(myValue)")
print("doubleValue call returns \\(doubleValue(myValue))")
print("After function call myValue = \\(myValue)")
- 이 코드는 myValue라는 이름의 변수에 10의 값으로 초기화하면서 시작한다.
- 그 다음에 새로운 함수를 선언하면서 정수형으로 하나의 매개변수를 받도록 선언한다.
- 함수는 값에 대한 섀도우 복사본을 생성하고 값을 2배로 만들고 반환한다.
var myValue = 10
func doubleValue(_ value: Int) -> Int {
var value = value
value += value
return value
}
print("Before function call myValue = \\(myValue)")
print("doubleValue call returns \\(doubleValue(myValue))")
print("After function call myValue = \\(myValue)")
// Before function call myValue = 10
// doubleValue call returns 20
// After function call myValue = 10
- 확실히 이 함수는 원본인 myValue 변수를 변경하지 않았다. 왜냐하면 myValue 변수가 아닌 복사본을 가지고 수학적 연산이 수행되었기 때문이다.
- 함수가 값을 반환한 뒤에도 매개변수에 대한 변경을 유지하려면, 함수 선언부 내에서 매개변수를 입출력 매개변수(in-out parameter)로 선언해야 한다.
- 그리고 함수 호출 입출력 매개변수 앞에 &를 붙여야 한다.
var myValue = 10
func doubleValue(_ value: intout Int) -> Int {
// var value = value
value += value
return value
}
print("Before function call myValue = \\(myValue)")
print("doubleValue call returns \\(doubleValue(&myValue))") // &이 붙었다.
print("After function call myValue = \\(myValue)")
// Before function call myValue = 10
// doubleValue call returns 20
// After function call myValue = 20 // 값이 변경되었다!!
inout과 &은 세트라고 생각하자.
매개변수인 함수
Swift에서는 함수가 데이터 타입처럼 취급될 수 있다.
- FloatString
- Tuple
- Double
- Int
- 다음의 선언부처럼 함수를 상수나 변수에 할당하는 것도 가능하다.
func inchesToFeet(_ inches: Float) -> Float {
return inches * 0.833333
}
let toFeet = inchesToFeet
위 코드는 inchesToFeet이라는 이름의 새로운 함수를 선언하고 그 함수를 toFeet이라는 상수에 할당한다.
이렇게 할당을 했다면, 원래의 함수 이름이 아니라 상수 이름을 이용하여 함수를 호출할 수도 있다.
let result = toFeet(10)
함수 이름을 갈아끼운다고 생각해보자. 구체적인 설명을 하면 길어지니까 메커니즘을 이해하기 위해 간단히 설명했다.
- 겉보기에는 그렇게 매력적인 기능이 아닌 것처럼 보인다.
- 왜냐하면 상수나 변수 데이터 타입에 함수를 할당하지 않아도 우리는 이 함수를 호출할 수 있기 때문에 큰 장점이 없어 보인다.
- 하지만, 상수나 변수에 할당된 함수는 여러 데이터 타입의 기능을 가질 수 있다는 점을 고려하면, 앞으로 이 기능은 많이 활용될 수 있을 것이다.
- 게다가 이제 함수는 다른 함수의 인자로 전달될 수 있으며, 함수의 반환값으로 반환될 수도 있다.
어떤 함수와 다른 함수를 어떻게 연결하는지에 대해 살펴보기 전에 먼저 ‘함수 데이터 타입’의 개념을 알아보자.
- 함수 데이터 타입?
- 받게 될 매개변수의 데이터 타입과 반환될 데이터 타입을 조합하여 결정된다.
- 앞의 예제에서 함수는 Float 형 매개변수를 받고 Float 형 결과를 반환하므로 함수의 데이터 타입을 아래와 같다.
func inchesToFeet(_ inches: Float) -> Float {
return inches * 0.833333
}
// 위 함수의 데이터 타입은 아래와 같다.
// (Float) -> Float
반면 Int와 Double을 매개변수로 받고 String 결과를 반환하는 함수는 다음의 데이터 타입을 가지게 된다.
(Int, Double) → String
📌 커피를 주문하는 예시를 살펴보자....
func orderStarbucks() -> String {
print("스타벅스 주문")
return "카라멜마끼야또"
}
func orderMegaCoffee() -> String {
print("메가커피 주문")
return "꿀아메리카노"
}
func orderHollys() -> Int {
print("할리스 주문")
// return "바닐라딜라이트"
return 100
}
var orderCafe: () -> String = orderStarbucks
print("손님 주문하신 \(orderCafe()) 나왔습니다")
orderCafe = orderMegaCoffee
print("손님 주문하신 \(orderCafe()) 나왔습니다")
let orderCafeNumber = orderHollys
print("\(orderCafeNumber()) 번째손님, 커피 나왔습니다")
- 어떤 함수가 다른 함수를 매개변수로 받기 위해서는 매개변수로 받게 될 함수의 데이터 타입을 선언하면 된다
- 예를 들어, 다음의 코드는 두 개의 함수를 상수에 할당한다.
func inchesToFeet(_ inches: Float) -> Float {
return inches * 0.833333
}
func inchesToYards(_ inches: Float) -> Float {
return inches * 0.0277778
}
let toFeet = inchesToFeet
let toYards = inchesToYards
- 이 예제코드는 단위를 반환하고 콘솔 패널에 결과를 출력하는 함수가 필요하다.
- 새롭게 만들 함수는 다양한 종류의 측정 단위를 변환할 수 있게 만들어 최대한 보편적인 함수가 되게 한다.
- 매개변수로 함수를 어떻게 사용하는지 확인하기 위해 새롭게 만들 함수는 inchesToFeet 함수 타입과 inchesToYards 함수 타입 모두와 일치하는 함수 타입과 함께 반환할 매개변수로 받을 것이다.
- 이들 함수의 데이터 타입은 (Float) → Float와 같기 때문에 우리의 새로운 함수는 다음과 같이 된다.
func inchesToFeet(_ inches: Float) -> Float {
return inches * 0.833333
}
func inchesToYards(_ inches: Float) -> Float {
return inches * 0.0277778
}
let toFeet = inchesToFeet
let toYards = inchesToYards
// outputConversion 함수
func outputConversion(_ converterFunc: (Float) -> Float, value: Float) {
let result = converterFunc(value)
print("Result of conversion is \\(result)")
}
- outputConversion 함수가 호출될 때 미리 선언한 데이터 타입과 일치하는 함수가 전달되어야 한다.
- 이 함수는 변환을 수행하고 그 결과를 콘솔 패널에 출력한다.
- 다시 말해, 적절한 변환 함수를 매개변수로 전달하기만 하면 인치를 피트로 변환하거나 야드로 변환할 때 동일한 함수를 호출할 수 있다는 의미이다.
// outputConversion 함수
func outputConversion(_ converterFunc: (Float) -> Float, value: Float) {
let result = converterFunc(value)
print("Result of conversion is \\(result)")
}
outputConversion(toYards, value: 10) // 야드로 변환하기
outputConversion(toFeet, value: 10) // 피트로 변환하기
- 이 함수는 불리언 매개변수의 값에 따라 우리가 만든 toFeet 함수나 toYards 함수 타입을 반환하도록 구성되어 있다.
func decideFunction(_ feet: Bool) -> (Float) -> Float {
if feet {
return toFeet
} else {
return toYards
}
}
func inchesToFeet(_ inches: Float) -> Float {
return inches * 0.833333
}
func inchesToYards(_ inches: Float) -> Float {
return inches * 0.0277778
}
let toFeet = inchesToFeet
let toYards = inchesToYards
클로저 표현식
꽤나 심각한 부분이다.
- 클로저(closure)와 클로저 표현식(closure expression)은 혼용되어 불리지만, 몇 가지 큰 차이점이 있다.
- 클로저 표현식은 독립적인 코드블록이다.
- 예) 다음은 클로저 표현식을 선언하고 그것을 sayHello라는 이름의 상수를 할당한 다음에 상수 참조를 통해 함수를 호출한다.
let sayHello = { print("Hello") } // (1)
sayHello()
func sayHello() { // (2)
print("Hello")
}
// (1)과 (2) 함수는 같은 의미이다.
함수형 언어의 특: 죽지 않는 프로그램이 되지만 작동을 시키면 꽤나 느리다. 그래서 함수 언어로 하면 속도가 느려서 비주류로 취급되었다. 그/런/데 컴퓨터가 빨리지고 죽지 않는 프로그램에 대한 수요가 늘고, 함수형언어의 특징을 각각의 언어들이 가지고 오게 된다!!
lambda, closure 같은 친구들이 함수형 언어의 특징이다.
- 클로저 표현식은 매개변수를 받아 결과값을 반환하도록 구성할 수도 있다.
{ (매개변수 이름: 매개변수 타입, 매개변수 이름: 매개변수 타입, ...) -> 반환결과 타입 in
// 클로저 표현식의 코드가 온다.
}
- 다음의 클로저 표현식은 두 개의 정수를 매개변수로 받아 하나의 정수를 결과로 반환한다.
let multiply = { (_ val1: Int, _ val2: Int) -> Int in
return val1 * val2
}
let result = mulitply(10,20)
- 이 구문은 함수를 선언할 때 사용하는 것과 비슷하지만
- 클로저 표현식은 이름을 가지지 않으며
- 매개변수와 반환타입은 괄호 안에 표현되고
- 클로러 표현식 코드의 시작을 가리키기 위하여 in 키워드를 사용한다.
- 사실, 함수는 이름이 있는 클로저 표현식일 뿐이다
Skip한 부분(읽어보자)
- 클로저 표현식은 비동기 메서드 호출에 대한 완료 핸들러를 선언할 때 종종 사용된다.
- 다시말해, iOS 앱을 개발할 때 어떤 작업을 백그라운드에서 작업하게 해서 앱이 다른 작업을 계속할 수 있도록 운영체제(iOS)에게 요청해야 하는 경우가 종종 생긴다.
- 이런 경우에는 보통 시스템이 앱에게 작업이 완료된 것을 알리고 작업(메서드)을 호출할 때 선언했던 완료 핸들러를 호출하여 결과를 반환한다.
- 완료 핸들러에 대한 코드는 주로 클로저 표현식의 형태로 구현된다.
evenstore.requestAccess(to: .reminder, completion: {(grandted: Bool, error: Erro?) -> Void in
if granted {
print(error!.localizedDescription)
}
}
- requestAccess(to:) 메서드 호출로 수행된 작업이 완료되면, completion: 매개변수로 선언된 클로저 표현식이 실행된다.
- 밑줄 그은 선언부와 같이 이 완료 핸들러는 불리언 값과 Error 객체를 매개변수로 받으면 아무런 결과도 반환하지 않는다.
다시 살펴보기
함수의 선언
1️⃣ 함수선언의 기본 형태
func 함수이름(매개변수1이름: 매개변수1타입, 매개변수2이름: 매개변수2타입 ... ) -> 반환타입 {
// 함수 구현부
return 반환값
}
// 예)
// sum이라는 이름을 가지고
// a와 b라는 Int 타입의 매개변수를 가지며
// Int 타입의 값을 반환하는 함수
func sum(a: Int, b: Int) -> Int {
return a+b
}
2️⃣ 반환 값이 없는 함수
func 함수이름(매개변수1이름: 매개변수1타입, 매개변수2이름: 매개변수2타입 ... ) -> 반환타입 {
// 함수 구현부
return
}
// 예)
func printMyName(name: String) -> Void {
print(name)
}
// 반환 값이 없는 경우, 반환 타입(Void)을 생략해 줄 수 있습니다.
func printYourName(name: String) {
print(name)
}
3️⃣ 매개변수가 없는 함수
func 함수이름() -> 반환타입 {
// 함수 구현부
return 반환값
}
// 예)
func maximumIntegerValue() -> Int {
return Int.max
}
4️⃣ 매개변수와 반환값이 없는 함수
func 함수이름() -> Void {
// 함수 구현부
return
}
// 함수 구현이 짧은 경우
// 가독성을 해치지 않는 범위에서
// 줄바꿈을 하지 ㅇ낳고 한 줄에 표핸해도 무관합니다.
func hello() -> void { print("hello") }
// 반환 값이 없는 경우, 반환 타입(Void)을 생략해 줄 수 있습니다.
func 함수이름() {
// 함수 구현부
return
}
func bye() { print("bye") }
5️⃣ 함수의 호출
sum(a: 3, b: 5) // 8
printMyName(name: "dadahae") // dadahae
printYourName(name: "kangvic") // kangvic
maximumIntegerValue() // Int의 최댓값
hello() // hello
bye() // bye
6️⃣ 매개변수 기본 값
// 매개변수에 기본적으로 전달할 값을 미리 지정할 수 있습니다.
// 기본값을 가지는 매개변수는 매개변수 목록 중에 뒤쪽에 위치하는 것이 좋습니다.
func 함수이름(매개변수1이름: 매개변수1타입, 매개변수2이름: 매개변수2타입 ... ) -> 반환타입 {
// 함수 구현부
return 반환값
}
func greeting(friend: String, me: String = "dadahae") {
print("Hello \\(friend)! I'm \\(me)")
}
// 매개변수 기본값을 가지는 매개변수는 호출 시 생략할 수 있습니다
greeting(friend: "kangvic") // Hello kangvic! I'm dadahae
greeting(friend: "jin", me: "dan") // Hello jin! I'm dan
7️⃣ 전달인자 레이블
// 함수를 호출할 때 함수 사용자의 입장에서 매개변수의 역할을 좀 더 명확하게 표현하고자 할 때 사용합니다
func 함수이름(전달인자 레이블 매개변수1이름: 매개변수1타입, 전달인자 레이블 매개변수2이름: 매개변수2타입 ...) -> 반환타입 {
// 함수 구현부
return
}
// 함수 내부에서 전달인자를 사용할 때에는 매개변수 이름을 사용합니다.
func greeting(to friend: String, from me: String) {
print("Hello \\(friend)! I'm \\(me)")
}
// 함수를 호출할 때에는 전달인자 레이블을 사용해야 합니다.
greeting(to: "kangvic", from: "dadahae") // Hello kangvic! I'm dadahae
8️⃣ 가변 매개변수
// 전달 받을 값의 개수를 알기 어려울 때 사용할 수 있습니다.
// 가변 매개변수는 함수당 하나만 가질 수 있습니다
func 함수이름(매개변수1이름: 매개변수1타입, 전달인자 레이블 매개변수2이름: 매개변수2타입...) -> 반환타입 {
// 함수 구현부
return
}
func sayHelloToFriends(me: String, friend: String) -> String {
print("Hello \\(friend)! I'm \\(me)")
}
print(sayHelloToFriends(me: "dadahae", friends: "kangvic", "bomi", "jin"))
// Hello ["kangvic", "bomi", "jin"]! I'm dadahae!
print(sayHelloToFriends(me: "dadahae")
// Hello []! I'm dadahae
데이터 타입으로서의 함수
1️⃣ 함수의 타입표현
스위프트는 함수형 프로그래밍 패러다임을 포함하는 다중 패러다임 언어이므로 스위프트의 함수는 일급 객체입니다.
함수의 타입을 표현할 때는 반환타입을 생략할 수 없습니다.
(매개변수1타입, 매개변수2타입 …) → 반환타입
var someFunction: (String, String) -> Void = greeting(to:from:)
someFunction("kangvic", "dadahae") // Hello kangvic! I'm dadahae
someFunction = greeting(friend:me:)
someFunction("kangvic", "dadahae") // Hello kangvic! I'm dadahae
// 타입이 다른 함수는 할당할 수 없다. 컴파일 오류가 발생한다.
//someFunction = sayHelloToFriends(me: friends:)
func runAnother(function: (String, String) -> Void) {
function("jenny", "rose")
}
// Hello jenny! I'm rose
runAnother(function: greeting(friend:me:))
// Hello jenny! I'm rose
runAnother(function: someFunction)
요약
함수, 메서드, 클로저
함수, 메서드, 클로저 표현식은 독립된 코드 블록으로 특정 작업을 수행하기 위하여 호출될 수 있으며, 코드를 구조화하고 재사용하는 메커니즘을 제공한다.
여기까지 배우고 함수, 메서드, 클로저를 이용하여 문제를 풀었다.
나도 Swift에 대해서 좀 안다고 생각했는데 겸손해지는 하루였다...
'외부활동 > 멋사 앱스쿨 1기' 카테고리의 다른 글
[TIL] 22-09-28: Swift (Inheritance, Subclassing, Extension) (0) | 2022.10.01 |
---|---|
[TIL] 22-09-27: Swift (객체지향 프로그래밍 기초) (0) | 2022.09.27 |
[TIL] 22-09-23: 오픈소스, Swift(반복문, 조건문) (0) | 2022.09.24 |
[TIL] 22-09-22: Swift (옵셔널, 연산자와 표현식) (1) | 2022.09.24 |
[TIL] 22-09-21: Swift 사전 지식(데이터타입/변수/상수/튜플) (1) | 2022.09.24 |