inout 파라미터 활용법

Eddy📱·2022년 6월 29일
0

Swift

목록 보기
9/11
post-thumbnail

inout 개념

Swift에서 파라미터는 상수이므로 함수 내부에서 값을 변경할 수 없다.

하지만, 이를 변경하고 싶을 때에는 inout 키워드를 활용해서 값을 변경할 수 있다.

이는 함수 호출이 종료된 후에도 적용된다.

inout 원리

  • 함수가 호출되면 매개변수로 넘겨진 변수가 복사된다.
  • 함수 몸체에서 복사한 값을 수정한다.
  • 함수가 반환될 때 변화된 값을 원본 변수에 재할당한다.

그러므로 이를 copy-in copy-out 이나 call by value result라고 부른다.

그래서 inout이 위의 말을 줄임말이라고 한다.

Swift는 값을 복사하는 것이 아니라 저장된 메모리 주소값을 함수 내부, 외부에서 사용한다.

이는 call by reference라고 한다.

이렇게 주소값만을 복사하므로 오버헤드를 줄일 수 있다고 한다.

memory 관리

inout를 사용 시, memory 접근에 주의해야한다.

var valueNumber = 1

func increase(_ count: inout Int) {
    count += valueNumber
}

함수 외부에서 존재하는 전역 변수를
inout 파라미테어 넣게 되면, 같은 메모리 주소를 참조하기 떄문에 읽기, 쓰기가 동시에 이루어져 충돌이 발생할 수 있다.

Simultaneous accesses to 0x103cb8090, but modification requires exclusive access.
Previous access (a modification) started at  (0x103ac43ac).
Current access (a read) started at:

이와 같은 에러가 발생한다. 읽기와 쓰기에서 충돌이 일어난 것이다!

그러므로 inout 파라미터를 캡쳐할 수 있는 클로저, 중첩함수는 반드시 nonescaping이어야 한다.

inout 파라미터로 캡쳐하길 원하면 캡쳐리스트를 통해 해당 파라미터를 불변 값으로 명시해야한다.

아래 처럼 코드를 통해 캡쳐리스트를 활용해서 해결할 수도 있다.

func decrease(count: inout Int) -> () -> Int {
    return { [count] in return count + 1 }
}

만약에 값을 캡쳐하고 변경을 원한다면 내부에서 복사해서 이를 직접 구현해야한다.

이에 대한 코드는 아래와 같다.

아래 처럼 local copy한 다음 직접 구현해주는 방식으로 할 수 있다

func multiply(queue: DispatchQueue, count: inout Int) {
    var localCount = count
    defer { count = localCount }
    
    queue.async {
        someMutationOpertaion(&localCount)
    }
    queue.sync { }
}

참고사이트

https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID545

profile
Make a better world

0개의 댓글