나의 기록, 현진록

[Swift] 13.4 값 획득 본문

Programming/Swift

[Swift] 13.4 값 획득

guswlsdk 2021. 9. 7. 09:27
반응형

스위프트 프로그래밍 3판 - 야곰 지음

 

13.4 값 획득

클로저는 자신이 정의된 위치의 주변 문맥을 통해 상수나 변수를 획득할 수 있습니다. 주변에 정의한 상수나 변수가 더 이상 존재하지 않더라도 값 획득을 통해 해당 상수나 변수의 값을 자신 내부에서 참조하거나 수정할 수 있습니다. 이 이야기를 하는 이유는 클로저가 비동기 작업에 많이 사용되기 때문입니다. 

 

클로저를 통해 비동기 콜백을 작성하는 경우, 현재 상태를 미리 획득해두지 않으면, 실제로 클로저의 기능을 실행하는 순간에는 주변의 상수나 변수가 메모리에 미리 존재하지 않는 경우가 발생합니다. 

 

중첩 함수도 하나의 클로저 형태라고 앞에서 설명했는데, 이 중첩 함수 주변의 변수나 상수를 획득해 놓을 수도 있습니다. 즉, 자신을 포함하는 지역변수나 지역상수를 획득할 수 있습니다.

 

incrementer라는 함수를 중첩 함수로 포함하는 makeIncrementer 함수를 살펴보겠습니다. 중첩 함수인 incrementer() 함수는 자신 주변에 있는 runningTotal과 amount라는 두 값을 획득합니다. 두 값을 획득한 후에 incrementer는 클로저로서 makeIncrementer 함수에 의해 반환됩니다.

 

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

 

 

makeIncrementer 함수는 반환 타입은 () -> Int입니다. 이는 함수 객체를 반환한다는 의미입니다. 반환하는 함수는 매개변수를 받지 않고 반환 타입은 Int인 함수로, 호출 할 때마다 Int 타입의 값을 반환해줍니다. incrementer가 반환하게 될 값을 저장하는 용도로 runningTotal을 정의했고, 0으로 초기화해두었습니다. 그리고 forIncrement라는 전달인자 레이블과 amount라는 매개변수 이름이 있는 Int 타입 매개변수 하나가 있습니다. incrementer() 함수가 호출될 때마다 amount 값만큼 runningTotal 값이 증가합니다. 

 

 

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

incrementer() 함수는 makeIncrementer(forIncrementer) 함수 외부에 독립적으로 떨어뜨려 놓으면 동작할 수 없습니다. runningTotal이라는 변수가 어디 있는지 찾아볼 수도 없습니다.

 

그러나 중첩 함수로 구현되어 있다면 runningTotal, amount 두 변수의 참조를 획득할 수 있습니다. 참조를 획득하면runningTotal, amount는 makeIncrementer 함수의 실행이 끝나도 사라지지 않습니다. 게다가 incrementer가 호출될 때마다 계속해서 사용할 수 있습니다. 

 


let incrementByTwo: (() -> Int) = makeIncrementer(forIncrementer: 2)
let incrementByTwo2: (() -> Int) = makeIncrementer(forIncrementer: 2)

let first: Int = incrementByTwo() //2
let second: Int = incrementByTwo() //4
let third: Int = incrementByTwo() //6

let first2: Int = incrementByTwo2() //2
let second2: Int = incrementByTwo2() //4 
let third2: Int = incrementByTwo2() //6

 

각각의 incrementer 함수는 언제 호출 되더라도 자신만의 runningTotal 변수를 갖고 카운트하게 됩니다. 왜냐하면 함수와 클로저는 참조 타입이기 때문입니다. 다른 함수의 영향도 전혀 받지 않습니다. 

반응형