Swift/Swift Language

Swift Language ) Closure

iosswift 2021. 10. 6. 18:43

1. Closures

1. Closures -

1.1  Closure Expressions

1.1.1 The Sorted Method

1.1.2 Closure Expression Syntax

1.1.3 Inferring Type From Context

1.1.4 Implicit Returns from Single-Expression Closures

1.1.5 Shorthand Argument Names

1.1.6 Operator Methods

 

1.2 Trailing Closures

1.3 Capturing Values

1.4 Closures Are Reference Types

1.5 Escaping Closures

1.6 Autoclosures

 

Closures 는 pass 가능하고 코드에서 사용가능한 self-contained blocks of functionality 에요. Closure 는 C 와 Objective-C 에서의 blocks, 그리고 다른 언어들에서의 lambdas 와 비슷합니다.

 

Closure 는 모든 constants 나 variables 에 대한 references 를 capture 및 store 가능합니다. (from the context in which they’re defined.) 

 

Swift 는 capturing 과 관련한 모든 메모리 관리를 대신 해줍니다.

 

 

Global functions 와 nested functions 도 closures 의 유형중 일부에요.  Closures 는 다음 세가지 형태 중 하나를 갖습니다.

  • Global functions 는 이름을 갖고, 어떠한 값도 capture 하지 않는 closure 입니다.
  • Nested functions 는 그 functions 을 포함하는 범위 내에서 이름을 갖고 values 를 capture 하는 closure 입니다.
  • Closure expressions 는 이름을 갖지 않고 간단한 문법을 갖는, 또한 values 를 capture 하는 ( from their surrounding context) closure 입니다. 

 

Swift 의 closure 는 많은 상황에서 아래와 같은 optimizations 를 갖기 때문에 clean, clear, brief 한 syntax 를 갖습니다.

  • Parameters, return value type 에 대한 inference (from context)
  • Implicit return( no need to write 'return' ) from single-expression closures 
  • shorthand argument 이름
  • Trailing closure

 

 

1.1 Closure Expressions

 

Nested functions 는 larger function 의 일부로,  self-contained blocks of code 를 정의하는 편리한 수단입니다. 하지만, 때에 따라서는 더 짧은 형태의 함수를 쓰는게 더 좋은 경우가 있습니다 ( full declaration, name 없이 ).  특히  functions 이 arguments 로 주어지는 functions, methods 를 다룰 때 더 그렇습니다. 

 

Closure expressions 은 간결한 syntax 를 갖는 closure 를 쓰는 방법 입니다.  Closure expressions 은 여러가지 syntax 의 최적화를 제공합니다. 아래 예시 sorted(by:) method 에서 코드를 차례차례 줄여가며 확인해보도록 하겠습니다. 

 

 

1.1.1 The Sorted Methods

 

Swift의 Standard library 에서는 sorted(by:) method 를 제공합니다. 이는 known type 의 values 를 갖고있는 array 에 대해 본인이 제공하는 sorting closure 에 따라 array 를 sort 하는 method 입니다. Sorting 과정이 끝나면 sorted(by:) mehtod 는 정렬된 형태의 기존 배열을 return 합니다. 이때, 기존 array 는 sorted(by:) method 에 의해 변하지 않습니다. 

 

아래는 알파벳 역순으로 배열 'names' 를 정렬하는 예시에 쓰일 배열입니다.

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

 

sorted(by:) method 는 같은 type 을 갖는 두 arguments 를 갖고 Bool 값을 return 하는 closure 를 받습니다. (첫번째 값과 두번째 값 중 어떤 값이 먼저 정렬되어야 하는지 알기위해 Bool 이 쓰이고, 첫번째 값이 먼저 나타나야 하는 경우 true 를 return 합니다. )

이 예제는 String values 를 갖는 array 를 sorting 하는 것이기 때문에, sorting closure 는 (String, String) -> Bool type 의 function 이어야 합니다. 

 

Sorting closure 를 제공하기 위한 방법 중 하나는 평상시처럼 function 을 작성하고, sorted(by:) method 의 argument 로 이 function 을 전달하는 것입니다. 

 

func backward(_ s1: String, _ s2: String) -> Bool { 
	return s1 > s2 
}

 

var reversedNames = names.sorted(by: backward)
// ["Ewa", "Daniella", "Chris", "Barry", "Alex"]

 

sorted(by areInIncreasingOrder: (String, String) throws -> Bool) rethrows -> [Int]

s1 > s2 인 경우 backward(_:_:) function 은 true 를 return하고, 이는 s1 이 s2 보다 먼저 sorted array 에 등장해야 한다는 것을 의미합니다. Character ( 또는 String) 에서 '>' 은 알파벳 상에서 더 늦게 나오는 것을 의미합니다 (B > A). backward(_:_:) 는 그러므로 sorted(by:) method 에 전달될 때 알파벳 역순으로 정렬시키는 function 으로 쓰입니다.  ( "Barry"가 "Alex" 보다 먼저 배치되게 됩니다. )  이 함수는 간단한 single-expression function 을 길게 쓴 것이기 때문에, 이 예시에서는 closure expression syntax 를 이용하여 sorting closure 를 inline 으로 바꾸어보겠습니다.  

 

 

1.1.2 Closure Expression Syntax

 

Closure expression syntax 는 일반적으로 다음과 같은 형태를 가지고있습니다. 

{ ( parameters) -> returnType in
    // statement
}

 

Closure expression 의 parameters 는 in-out parameters 를 가질 수 있으나, default value 는 가질 수 없습니다.

Variadic parameters 에 대해서는 variadic parameter 에 이름을 붙여준다면 사용가능하고,

Tuples 는 parameter types, 그리고 return types 으로 쓸 수 있습니다. 

 

아래 예시는 closure expression 을 사용한 backward(_:_:) function 입니다.

reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

 

Parameters , return type 에 대한 declaration 은 backward(_:_:) function 에서와 같습니다. 두 가지 경우 모두 (s1: String, s2: String) -> Bool 은 같으나, inline closure expression 에서는 parameters 와 return type 이 중괄호 '{ }' 안에서 쓰여졌습니다. 그리고, closure 의 body 부분은 'in' 뒤에서 시작되었습니다.  'in' keyword 는 closure 의 parameters, return type 에 대한 정의가 끝났고, 이제 closure 의 body 부분이 시작될 것임을 의미합니다. Closure 의 body 부분이 짧아졌기 때문에 한줄로 표현해보도록 하겠습니다. 

reversedNames = names.sorted(by: {(s1: String, s2: String) -> Bool in return s1 > s2 })

전체 function 은 동일하지만, 이제 inline closure 가 되었습니다. 

 

 

1.1.3 Inferring Type From Context

 

Sorting closure 가 method 의 argument 로 넘겨졌기 때문에 Swift 는 parameters, return value 의 types 에 대해 추론할 수 있습니다. sorted(by:) method 가 [String] 에서 호출되었기 때문에, argument는 반드시 (String, String) -> Bool  type 을 갖는 function 이어야 합니다. 다시 말하면, (String, String) 그리고 Bool 은 closure expression 의 definition 에서 굳이 쓰여지지 않아도 됩니다. 모든 types 이 어떤 것인지 알 수 있기때문에, return arrow (->) 와 parameters의 이름들을 감싸는 괄호들도 생략될 수 있습니다.  

reversedNames = names.sorted(by: {(s1: String, s2: String) -> Bool in return s1 > s2 })
// before
reversedNames = names.sorted(by: {s1, s2 in return s1 > s2 })
// after

Function 이나 method 에 inline closure expression 을 통해 closure 를 pass 할 때 parameter와 return type 에 대해서 항상 infer 할 수 있습니다. 그렇기 때문에 closure 가 function 이나 method 의 argument 로 사용될 때, inline closure 는 모든 요소가 다 포함되어있는 형태로 쓸 필요가 없습니다. 

 

그렇지만 원하거나, Type 을 추론하기 애매하다면  types 을 명시해 줌으로써 code 를 읽기 쉽게 할 수 있습니다. sorted(by:) method 의 경우, closure 의 목적이 분명하기 때문에 type 을 유추하기 쉽고 따라서 이 경우 생략해도 괜찮을 것입니다. 

 

 

1.1.4 Implicit Returns from Single-Expression Closures

 

Single-expression closures 를 사용할 때는 'return' keyword 를 생략해도 됩니다. 

reversedNames = names.sorted(by: {s1, s2 in s1 > s2 })

 

sorted(by:) method  argument 의 function type을 통해 closure 가 Bool value 를 return 할 것임을 알 수 있습니다. Closure's body 가 Bool value 를 return 하는 single expression 을 갖고있기 때문에,  'return' keyword 가 생략될 수 있습니다. 

 

 

1.1.5 Shorthand Argument Names

 

// Anonymous closure arguments cannot be used inside a closure that has explicit arguments

 

Swift 는 자동으로 shorthand argument names 를 inline closures 에 대하여 제공하고, 이것들은 closure의 arguments 값들을 가리키는 데에 사용될 수 있습니다. ($0, $1, $2, ...)  Shorthand argument names 를 closure expression 내에 사용할 때, closure's argument list 를 정의에서 제거할 수 있습니다. Shorthand argument names 의 type 은 제공될 function 의 type 으로부터 알게되고, argument list 에 넣어야 했던 양 만큼의 shorthand arguments 를 사용할 수 있습니다. Closure 가 이제 body 로만 구성되기 대문에, 'in' keyword 를 쓰지 않아도 됩니다. 

 

reversedNames = names.sorted(by: {s1, s2 in s1 > s2 }) // before
reversedNames = names.sorted(by: {$0 > $1 })	       // after

 

여기에서 $0 과 $1 는 각각 closure 의 첫번째, 두번째 String argument 를 가리킵니다. $1 가 가장 높은 숫자를 가지고 있는 shorthand argument 이기때문에, closure 는 2개의 arguments 를 받는다는 것을 알 수 있습니다. sorted(by:) function 은 arguments 가 모두 String type 인 closure 를 받을 것을 알기 때문에, $0 과 $1 는 String type 입니다. 

 

 

1.1.6 Operator Methods

 

위 closure expression 보다 더 짧게 쓰는 방법도 있습니다. Swift 의 String type 은 두개의 String type parameters 를 갖고, Bool type 의 value 를 return 하는 method 인  '>' 을 사용할 수 있습니다. 

Swift’s String type defines its string-specific implementation of the greater-than operator (>) as a method that has two parameters of type String, and returns a value of type Bool.

reversedNames = names.sorted(by: > )

 

 

 

 

 

1.2 Trailing Closures

 

만약 function 의 마지막 argument 로 closure expression 을 넘겨주어야 하고, closure expression 이 길어질 경우 trailing closure  를 사용하는게 편할 수 있습니다. function call 후 괄호를 끝내고나서 trailing closure 를 쓰면 됩니다. Trailing closure syntax 를 사용할 때, 첫번째 closure 에 대해서는 argument label 을 써주지 않습니다.  Function 은 여러개의 trailing closures 을 포함할 수 있습니다. 

 

func someFunctionThatTakesAClosure(closure: () -> Void) {
    //function body goes here
}
// Here's how you call this function without using a trailing closure:

someFunctionThatTakesAClosure(closure: {
	// closure's body goes here
})
// Here's how you call this function with a trailing closure instead:

someFunctionThatTakesAClosure() {
    // trailing closure's body goes here
}

 

String-sorting closure (전 예시) 는 아래와 같이 trailing closure 로, sorted(by:) method 의 바깥쪽에 쓸 수 있습니다.

 

reversedNames = names.sorted() { $0 > $1 }

 

만약 closure expression 이 function or method 의 유일한 argument 이고, expression 을 trailing closure 를 통해 pass 할 경우, 호출할 때 function 이름 뒤에 보통 붙여주는 '()' 는 생략할 수 있습니다.  

 

reversedNames = names.sorted { $0 > $1 }

 

Trailing closures 는 closure 가 inline 으로 쓰기 힘들만큼 길어질 때 쓰면 아주 유용합니다. 예시로, Swift's Array type 은 map(_:) method 를 가지고 있는데, 이 method 는 closure expression 하나만을 argument 로 갖습니다. 각 array 의 item 마다 closure 가 한번씩 실행되면서 mapped value (closure 에 의해 변형된 item) 를 return 합니다.  ( 다른 type 을 return 할 수도 있습니다.) map(_:) 의 closure 에  return type 과 mapping 방법과 을 적어주는 방식으로 이용합니다. 

각 array element 에 closure 을 적용한 후, map(_:) method 는 original values 를  mapping 한 values 을 순서대로 가지는 새로운 array 를 반환합니다. 

 

 

아래는 map(_:) method 를 trailing closure 와 함께 사용해서 [Int] array 를 [String] array 로 변환하는 예시입니다. 

 ( [16, 58, 510] -> ["OneSix", "FiveEight", "FiveOneZero"] )

 

let digitNames = [
    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map { (number) -> String in
    var number = number
    var output = ""
    repeat {
        output = digitNames[number % 10]! + output
        number /= 10
    } while number > 0
    return output
}
// strings is inferred to be of type [String]
// its value is ["OneSix", "FiveEight", "FiveOneZero"]

 

map(_:) method 가 각 item 마다 closure 를 호출합니다. 이때, closure's input parameter (number) type 은 지정해주지 않아도 array 내에 있는 value 의 type 으로 inferred 됩니다. Function 과 Closure 의 Parameters 는 constant 이므로 var number 을 선언 후 이용하였습니다. 

 

 

만약 function 이 여러개의 closures 를 취할 경우, 첫번째 trailing closure 의 argument label 을 생략할 수 있습니다. 

아래 함수는 서버로부터 사진들을 받아오는 기능을 수행합니다.  

func loadPicture(from server: Server, completion: (Picture) -> Void, onFailure: () -> Void) {
    if let picture = download("photo.jpg", from: server) {
        completion(picture)
    } else {
        onFailure()
    }
}

 

 

이 함수를 쓰기 위해선 서버 외에도 두개의 closures 가 주어져야 합니다. 첫번째 closure 는 사진이 성공적으로 다운로드 되었을 때 보여주는 completion handler 이고, 두번째는 실패했을 때 user 에게 error 가 발생했음을 알리는 error handler 입니다. 

 

loadPicture(from: someServer) { picture in
    someView.currentPicture = picture
} onFailure: {
    print("Couldn't download the next picture.")
}

// trailing closure

 

loadPicture(from: someServer, completion: { picture in 
	someView.currentPicture = picture
}, onFailure: { 
	print("fail")
})
// without trailing closure

위 예시에서 (with trailing closure) 첫번째 closure (completion) 의 argument label 은  trailing closure 를 사용함에 따라 생략되었음을 볼 수 있습니다. 

 

loadPicture function 은 network task 를 background 로 보내고, network task 가 finish 했을 때 두 completion handlers 중 하나를 호출합니다. function 을 이러한 방식으로 만들면 두가지 상황에 대해 하나의 closure 로 처리하는 방식보다 깔끔하게 두 상황을 분리할 수 있습니다. 

 

 

 

Capturing Values

Closure 는 constants, variables 를 capture 할 수 있습니다. (from the surrounding context in which it's defined) 그 후 Closure 는 body 내에서 capture 된 values, constants 를 변형하거나 가리킬 수 있습니다. (even if the original scope that defined the constants and variables no longer exists)  

 

Swift 에서 value 를 capture 하는 가장 단순한 형태의 closure 는 nested function 입니다. (함수 내에 정의) Nested function 은 자신 밖에 존재하는 function 의 arguments, 그리고 variables 와 constants에 대해  capture 할 수 있습니다. 

 

incrementer function 을 내포하는 makeIncrementer function 을 예시로 더 자세히 알아보도록 하겠습니다. incrementer() function 은 두 runningTotal, amount 를 capture 합니다. (from its surrounding context) Capture 한 후에 incrementer 함수는 makeIncrementer 의 closure (runningTotal 을 호출될 때마다 amount 만큼 증가시키는) 로 return 됩니다. 

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

 

  • makeIncrementer function 의 return type 은 () -> Int 입니다. 이것은 단순한 value 가 아닌 function 을 return 합니다. return 하는 function 은 parameters 가 없으며, 호출될 때마다 Int 값을 return 합니다. 
  • makeIncrementer(forIncrement:) 는 현재 incrementer 의 running total 을 저장하기 위해 runningTotal 이라는 integer 를 정의하고,  이 integer 는 0 을 초기값으로 가집니다. 
  • makeIncrementer(forIncrement:) 은 argument label 로 forIncrement , parameter name 으로 amount 를 가지는 하나의 Int parameter 를 갖습니다.  해당 parameter 에 전해지는 argument value 는 incrementer function 이 호출될 때마다 얼마의 runningTotal 값이 증가해야 하는지를 정합니다.
  • makeIncrementer function은 incrementer 라는 nested function 을 정의하고, incrementer 은 값을 증가시킵니다. (amout 를 runningTotal 에 더한 후 결과를 return 합니다.) 

 

따로 nested incrementer() function 을 떼어놓고 봤을 때, 보통의 함수들과는 약간 다르게 생긴 것 같습니다.

func incrementer() -> Int {
    runningTotal += amount
    return runningTotal
}

 

 

incrementer() function 은 어떠한 parameters 도 갖지 않지만, function body 내에 있는 runningTotal 과 amount 를 refer 합니다. 이 함수는 주변 function 에 있는 runningTotal 과 amount 에 대한 reference 를 capture 함으로써 두 값을 refer 할 수 있고, 자신의 function body 내에서 사용할 수 있습니다. Reference 를 통해 Capture 함으로서 runningTotal 과 amount 가 makeIncrementer  호출이 끝나고도 남아있을 수 있고, incrementer function 이 나중에 다시 호출될 때에도 runningTotal 은 여전히 이용가능합니다.  

 

As an optimization, Swift may instead capture and store a copy of a value if that value isn’t mutated by a closure, and if the value isn’t mutated after the closure is created.

Swift also handles all memory management involved in disposing of variables when they’re no longer needed.

아래는 makeIncrementer function 의 예시입니다. 

 

최적화를 위해서,  Swift 는 만약 value 가 closure 에 의해 변하지 않는다면, 그리고 closure 가 만들어진 후에 변하지 않는다면  value 의 복사본을 capture, store 합니다.
Swift 는 variables 가 더이상 사용되지 않을 때, 값에 대한 메모리 관리를 합니다. 
let incrementByTen = makeIncrementer(forIncrement: 10)

 

예시에서 incrementByTen constant 를  호출 될 때마다 runningTotal variable 10씩 증가시키는 function incrementer 을 refer 하도록 설정하였습니다. 이때, incrementByTen 의 type 은 () -> Int 입니다.

incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30

만약 새로운 incrementer 함수를 만들게 되면, 그 함수는 전과 다른, 새로운 이 함수만의 runningTotal 를 stored reference 로 갖게됩니다. 

let incrementBySeven = makeIncrementer(forIncrement: 7)
incrementBySeven()
// returns a value of 7

기존에 만들었던 incrementByTen 함수를 호출하면 이 함수만의 runningTotal 을 다시 증가시키게 되고, incrementBySeven 함수에 의해 capture 된 reference 에는 영향을 미치지 않습니다. 

incrementByTen()
// returns a value of 40

 

더보기

만약 class instance 의 property 에 closure 를 할당하고 closure 가 그 instance 를 (instance or its members 를 refer 함으로서) capture 하게되면, strong reference cycle 을 closure 와 instance 사이에 생성하게됩니다. Swift 는 capture lists 를 이러한 strong reference cycles 를 없애기 위해 사용합니다.

 

 

 

Closures Are Reference Types

 

 

This also means that if you assign a closure to two different constants or variables, both of those constants or variables refer to the same closure.

 

위 예시들에서, incrementBySeven 과 incrementByTen 은 모두 constants 이지만, 두 constants 가 refer 하는 closures 는 capture 하고있는 runningTotal variables 를 증가시킬 수 있습니다. 이는 functions 과 closures 가 reference types 이기 때문에 가능합니다. 

Function 이나 closure 를 constant, variable 에 할당 하는 것은 해당 변수를 function, closure 에 대한 reference 로 설정하는 것과 같습니다.

it’s the choice of closure / that incrementByTen refers to / that’s constant, and not the contents of the closure itself.

??위 예시에서, closure 에 달렸습니다. incrementByTen closure 의 contents 자체가 아닌 constant 를 refer 하는 것은 ?????????

이것은 두 constants 나 variables 에 closure 를 할당할 때, 두개 모두 같은 closure 를 refer 한다는 것을 의미하기도 합니다. 

let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// returns a value of 50

incrementByTen()
// returns a value of 60

 

Escaping Closures

 

asynchronous 

Function 에 closure 가 argument 로 전해지지만 function 이 return 한 뒤에 closure 가 호출 되는 경우, closure 가 function 을 escape 한다 고 말합니다. Parameters 중 하나로 closure 를 받는 function 을 선언할 때, '@escaping' keyword 를 parameter 의 type 앞에 써주면 closure 가 escape 할 수 있다는 것을 의미하게 됩니다. 

 

Closure 가 escape 할 수 있는 경우 중 하나는 function 의 바깥에서 선언된 variable 에 할당된 경우입니다. 그 예시로, asynchronous operation 을 시작하는 많은 functions 이 completion handler 로 closure 를 받습니다. Function은 operation 을 시작한 후 return 되지만, closure 는 operation 이 끝날 때까지 호출되지 않습니다. — closure 가 이후에 호출되기 위해서는 escape 해야합니다. — 

 

var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}

 

someFunctionWithEscapingClosure(_:) function 은 closure 를 argument 로 받고, 이를 function 밖에서 선언된 array 에 저장합니다. 만약 @escaping 을 붙이지 않는다면, compile-time error 를 맞이하게 될겁니다. self 를 refer 하는 escaping closure 는 만약 self 가 class 의 instance 인 경우 조심하여 사용하여야 합니다. Escaping closure 에서 self 를 Capturing 할 때에는 strong reference cycle 을 생성하기 쉽습니다. 

 

보통 closure 는 variables 를 closure 의 body 내에서 사용하면서 implicitly capture 하게 되지만,  explicit 하게 표기해주시는게 좋습니다. self 를 capture 할 때, self 를 명시적으로 써주거나, closure's capture list 에 self 를 포함시켜주세요. Self 를 표기하면서 본인의 의도를 알리고, reference cycle 을 만들지 않도록 다시 한번 확인해주세요.

 

아래 someFunctionWithEscapingClosure(_:)  에 전달된 closure 는 self 를 명시적으로 가리켰지만, someFunctionWithNonescapingClosure(_:) 에 전달된 closure 는 nonescaping closure 이고, 따라서 self 를 implicitly 가리킬 수 있습니다. 

/*
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}
*/

func someFunctionWithNonescapingClosure(closure: () -> Void) {
    closure()
}

class SomeClass {
    var x = 10
    func doSomething() {
        someFunctionWithEscapingClosure { self.x = 100 }
        someFunctionWithNonescapingClosure { x = 200 }
    }
}

let instance = SomeClass()
instance.doSomething()
print(instance.x)
// Prints "200"

completionHandlers.first?()
print(instance.x)
// Prints "100"

 

아래는 closure's capture list 에 self 를 capture 한 doSomething() 이고, self 를 implicitly refer 합니다. 

class SomeOtherClass {
    var x = 10
    func doSomething() {
        someFunctionWithEscapingClosure { [self] in x = 100 }
        someFunctionWithNonescapingClosure { x = 200 }
    }
}

 

 

만약 self 가 structure 또는 enumeration 의 instance 인 경우, 언제나 self 를 implicitly refer 할 수 있습니다. 그러나, escaping closure 는 self 가 structure 나 enumeration 의 instance 인 경우 mutable reference to self 를 capture 할 수 없습니다. Structures 와 enumerations 는 shared mutaility 를 허용하지 않습니다.  

struct SomeStruct {
    var x = 10
    mutating func doSomething() {
        someFunctionWithNonescapingClosure { x = 200 }  // Ok
        someFunctionWithEscapingClosure { x = 100 }     // Error
    }
}

 

 

someFunctionWithEscapingClosure function 의 호출은 mutating method 내에 있기 때문에 (self is mutable) error 를 발생시킵니다.  왜냐하면, escaping closure 는 (structure 에서) self 에 대한 mutable reference 를 capture 할 수 없기 때문입니다. 

 

 

AutoClosures

 

출처: https://docs.swift.org/swift-book/LanguageGuide/Closures.html