[swift] swift 기본 문법 스터디 7주차

[swift] swift 기본 문법 스터디 7주차

일급 객체로서의 함수

  • 특성
    • 런타임에서 생성가능
    • 인자값으로 객체 전달가능
    • 반환값으로 객체를 사용할 수 있어야 함
    • 변수, 데이터 구조 안에 저장
    • 고유한 구별이 가능

변수나 상수에 함수를 대입할 수 있음

함수의 결과값을 변수나, 상수에 대입하는 것이 아는 그 자체를 변수나 상수에 대입할 수 있습니다.

func printAddFive(base: Int) -> String {
  return "결과 값은 \(base)입니다."
}
let fnc1 = printAddFive(base: 4)
// 결과 값은 9입니다.

위의 예제는 함수를 선언하고, 그 함수의 결과값을 변수에 저장하는 예제 입니다.

let fnc2 = printAddFive
fun2(5)
// 결과 값은 10입니다.

이렇게 함수 자체를 대입하고, 인자를 넣어서 호출 할 수 있습니다. 하지만 왜 _ 이렇게 라벨을 없애지 않았는데 없어진 걸까요?

변수를 대입하는데에 타입이 필요하고, 같은 타입에 연산이 가능 하듯이 함수도 마찬가지 입니다. 함수도 함수 타입이 있습니다.

(인자타입1, 인자타입2) -> 반환타입

우리가 위에서 만든 printAddFive 함수의 타입을 적어보면, (Int) -> String이 되겠군요.

함수의 반환타입으로 함수를 사용할 수 있음

함수의 반환에는 자료형이나, 클래스, 구조체 뿐만 아니라 함수도 반환할 수 있습니다. 그러면 어떻게 생겼을까요?

func desc() -> String {
  return "desc 함수입니다."
}

func pass() -> () -> String {
  return desc
}

let p = pass()
p()
// desc 함수입니다.

위의 예제 코드를 보면, pass 함수는, () -> String 이라는 함수를 반환 합니다. 그리고 그 함수의 이름은 desc 입니다. 그렇기 때문에 pass 함수를 호출 한 결과를 p 변수에 넣으면 desc 함수가 들어가 있고, 실행하면 desc 함수입니다. 가 출력됩니다.

앞에서 부터 읽어나가거나, 뒤에서 부터 읽어나갈 때 ->를 기준으로 끊어 인자 부분과 반환 부분을 구분해서 읽으면 편합니다.

함수의 인자값으로 함수를 사용할 수 있음

정수나, 배열, 구조체 이외의 함수를 전달인자에 넣어 인자 값으로 사용 할 수 있습니다.

func printSuccess() {
  print("성공")
}

func printFail() {
  print("실패")
}

func devide(base: Int, success sCallBack: () -> Void, fail fCallBack: () -> Void) -> Int {
  guard base != 0 else {
    fCallBack()
    return 0
  }

  defer {
    sCallBack()
  }
  return 100 / base
}

devide(base: 50, success: printSuccess, fail: printFail)
// 성공

위의 예제에서 defer 키워드를 이용해 함수의 종료 직전에 실행 되는 구문을 만들어 callback 함수를 구현할 수 있습니다. 이렇게 함수를 인자로 넘기는 이유는, 함수 내부의 코드를 건드리지 않고 외부에서 실행 흐름을 추가하기 위함 입니다. 이미 작성된 코드를 수정하면, 내가 작성한 코드로 인해 전체 함수가 제대로 동작 하는지 테스트를 해야합니다. 하지만 인자로 넘겨서 동작하게 한다면 기존의 코드는 품질을 보장한 채로 내가 작성한 코드만 테스트 해도 됩니다. 이렇게 하면 함수의 재 사용성이 증가합니다.

인자값으로 사용하기 위해 재 사용되지 않는 함수를 작성하는 것은 비 효율적이기 때문에 1회용 함수인 익명 함수도 지원합니다. 스위프트에서는 이를 클로져라고 부릅니다.

중첩 함수

스위프트는 함수안에 함수를 선언할 수 있습니다. 내부함수와 외부함수로 구분되며, 내부함수는 외부함수가 실행될 때 생성되고 내부함수가 종료되는 순간 소멸됩니다.

func outer(base: Int) -> String {
  func inner(inc: Int) -> String {
    return "inc는 \(inc)"
  }

  let result = inner(inc: base + 1)
  return result
}

outer(base: 3)

inner라는 함수는 outer함수 내에서만 참조 될 수 있도록 은닉 되어있습니다. 외부함수는 참조 카운트가 0 -> 1이 되는 순간 생성되어서 0이 되는순간 소멸합니다. 하지만 내부 함수는 외부함수 내부에서만 참조 될 수 있기 때문에 외부함수에 의존합니다. 외부 함수가 내부 함수를 참조하면 생성되어 외부 함수가 종료되면 내부 함수도 소멸됩니다.

댓글

이 블로그의 인기 게시물

[IOS] AppDelegate는 뭐하는 녀석이지?

[git] git의 upstream과 origin 헷갈리는 사람 손!

[git] Github 이슈 라벨(issue labels)