DADAHAE's Log
비싼 장난감 가지고 노는 중 (❁´▽`❁)*✲゚*
[TIL] 22-09-26: Swift (함수, 메서드, 클로저)
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에 대해서 좀 안다고 생각했는데 겸손해지는 하루였다...

 

 

 

 

 

 

 

  Comments,     Trackbacks