-
Swift #13 - 클로저Swift의 온도 2021. 1. 21. 01:49
1. 클로저와 함수 타입
- 클로저
#클로저란?
*클로저는 함수 객체
*클로저 형태 : 함수나 코드 블록
*클로저가 정의된 콘텍스트까지 포함
- 함수 객체
*함수 정의func sayHello() {print("Hello")}*함수 호출sayHello()*함수 참조var hello = sayHellohello()*파라미터로 사용하기var hello = sayHellogreet(hello)*함수 파라미터 정의?func greet(_ arg : ????) {}cs - 함수 타입
*함수 객체를 참조 변수로 사용할 때의 타입
*파라미터로 사용할 때
*함수 타입 : 함수의 구성 요소인 파라미터, 반환 타입으로 구성
#함수 타입의 예시
*파라미터 없고, 반환 값 없는 함수 : () -> ()func sayHello() {}*()대신 Void 사용 가능 : () -> Voidcs *파라미터 없고, 반환 값 없는 함수 : () -> ()func sayHello() {}*()대신 Void 사용 가능 : () -> Void*파라미터와 반환 값이 없는 함수 타입*(String) - > ()func sayByeBye(who : String) {}*(String, String) -> ()func say(who : String, what : String){}*파라미터와 반환 타입이 있는 함수 타입*(Int, Int) -> Intfunc add(i : int, j : Int) -> Int {return i + j}cs #같은 타입의 함수
*다음 두 함수는 같은 함수 타입 : (Int, Int) -> Intfunc add(i : Int, j : Int) -> Int {return i + j}func multiply(i : Int, j : Int) -> Int {return i * j}cs - 클로저 사용하기
#클로저를 사용하는 API
*Array의 sort 메소드, 파라미터 타입func sorted(by order : (Element, Element) -> Bool) -> [Element]*Array<Int>의 경우 : (Int, Int) -> Bool*함수 타입에 맞는 함수func sortFunc(a : Int, b : Int) -> Bool {return a < b}*Array의 sort 함수에 사용하기let sorted = array.sorted(by : sortFunc)cs - 클로저 표현식
*별도의 함수 정의 없이 Inline 방식으로 작성{( PARAMETERS) -> RETURN_TYPE in//코드}*예시array.sorted(by:{(a : Int, b : Int) -> Boolinreturn a < b})cs #클로저 표현식 단축
*타입 선언 생략array.sorted(by: { a,b -> Bool in return a < b } )*1줄 return 인 경우 -> return 생략array.sorted(by: { a,b -> Bool in a < b } )*반환 타입 선언 생략array.sorted(by: { a,b in a < b})*파라미터 선언 생략array.sorted(by: { $0 < $1 })cs - 클로저 축약
#Tailing Closure
*클로저 파라미터가 마지막인 경우*괄호 밖에 작성*외부 파라미터 사용 생략array.sorted(by: { a, b in a a < b } )array.sorted(){ a, b in a < b } )*파라미터가 클로저 1개 -> 괄호식도 생략array.sorted { a, b in a < b}cs 2. 클로저 API 작성하기
- 클로저 사용 API
#클로저를 사용하는 API 작성하기
*클로저의 함수 타입 결정
*반환 값으로 사용
*파라미터로 사용
*프로퍼티에 사용
#반환 값으로 정의하기
*반환 값의 함수 타입 : () -> ()func greeting() -> () -> () {func sayGoodmorning() {print("Good Morning")}return sayGoodmorning}*호출let ret = greeting()ret()*클로저 표현식으로 작성하기func greeting() -> (() -> ()) {return { () -> () inprint("How are you?")}}*축약하기func greeting() -> () -> () {return {print("How are you?")}}cs #파라미터에 사용하기
*기존 함수func add(_ i : Int _ j : Int) -> Int {let sum = i + jreturn sum}let ret = add(1,2)*함수파라미터로 선언*함수 내부에서 호출func add(_ i : Int _ j : Int, _ handler: (Int) -> Void ) {let sum = i + jhandler(sum)}*사용하기add(3, 4, { (result : Int) -> Void inprint("3 + 4 = \(result)")})*파라미터 타입 선언 생략, 반환 타입 선언 생략add(3, 4, { result inprint("3 + 4 = \(result)")})*파라미터 선언 생략, Trailing Closureadd(3, 4, { ( result inprint("3 + 4 = \(result)")}cs - 클로저 사용 API
#클로저와 옵셔널
*파라미터 타입 : 클로저 옵셔널func multiply(_ i : Int _ j : Int,_ handler : ((Int) -> Void)?)*반환 타입 : 클로저 옵셔널func sayHello() -> (() -> ())? {return nil}cs #프로퍼티로 클로저
*클래스 프로퍼티 타입으로 함수 타입class MyClass {var property : ( () -> Int )!}*프로퍼티에 값(클로저) 설정var obj = MyClass()obj.property = {return 0}cs - 커스텀 타입 내 접근
#클로저에서 프로퍼티 접근
*클로저에서 프로퍼티 접근 : self 사용class MyClosureClass {var value = 0func showAndPrint() -> () -> () {return {print(self.value)}}}cs 3. 클로저와 캡처
- 클로저
#클로저 : 함수 + 객체
*클로저 생성 환경 ! = 클로저 실행 환경
*클로저가 정의된 환경(컨텍스트)을 캡처(Capture)
- 클로저 컨텍스트
*클로저 정의된 부분에서 접근 가능한 객체 (읽기)func greeting() -> () -> () {let str = "Hello"return {print(str)}}*호출하기 - 출력되는 str의 값은?let str = "Good Morning"let ret = greeting()ret()cs #클로저 캡처
*값 변경하기func increment(by amount : Int) -> () -> () {var count = 0returncount += amountprint(count)}}cs - 레퍼런스 타입 캡처
#레퍼런스 타입 객체 캡처
*클래스 정의class MyClass {var value = 0}*클로저func increment2(by amount : Int) -> () -> () {let obj = MyClass()return {obj.value += amountobj.printValue()}}cs 4. escaping, autoclosure
- escaping, noescaping
#noescaping
*함수 파라미터로 클로저 전달*함수 외부에 사용 금지(기본값)*프로퍼티로 설정 - 에러class MyClass {var prop : (() -> ())!func closureFunc(_ arg : () -> () ) {}}*다른 함수 파라미터로 호출 : 가능*noescaping -> noescaping 으로 전달 가능func closureFunc(_ arg : () -> () ) {otherFunc(arg)}func otherFunc(_ arg : () -> () ) {arg()}cs #escaping
*파라미터 타입에 @escaping 작성*파라미터 클로저를 함수 외부에 사용하기class MyClass2 {var prop : (() -> ())!func closureFunc(_ arg : @escaping () -> () ) {self.prop = arg}}cs #escaping 파라미터
*noescaping에서 escaping 함수 파라미터 대입은 불가func closureFunc(_ arg : () -> () ) {otherFunc(arg) // Error}func otherFunc(_ arg : @escaping () -> () ) {arg()}cs - autoclosure
#autoclosure
*파라미터가 없는 표현식을 클로저로 변환*파라미터가 없는 클로저func dolt(_ arg : () -> () ) { // Code }dolt( {value += 10} )*Auto Closure - 파라미터func dolt2(_ arg : @autoclosure () -> () ) { // Code }dolt2( value += 10 )cs #autoclosure는 모두 noescape
*autoclosure를 escaping 으로 선언하기var escapedVar : (() -> () )!func dolt3(_ arg : @autoclosure @escaping () -> () ) {arg()escapedVar = arg}dolt3( value += 10 )cs 'Swift의 온도' 카테고리의 다른 글
Swift #15 - 에러처리 (0) 2021.01.26 Swift #14 - 프로토콜, extension (0) 2021.01.22 Swift #12 - 구조체와 Enum (0) 2021.01.20 Swift #11 - 메모리 관리 (0) 2021.01.19 Swift #10 - 상속 (0) 2021.01.15