Swift에서 파라미터는 상수이므로 함수 내부에서 값을 변경할 수 없다.
하지만, 이를 변경하고 싶을 때에는 inout
키워드를 활용해서 값을 변경할 수 있다.
이는 함수 호출이 종료된 후에도 적용된다.
그러므로 이를 copy-in copy-out 이나 call by value result라고 부른다.
그래서 inout이 위의 말을 줄임말이라고 한다.
Swift는 값을 복사하는 것이 아니라 저장된 메모리 주소값을 함수 내부, 외부에서 사용한다.
이는 call by reference라고 한다.
이렇게 주소값만을 복사하므로 오버헤드를 줄일 수 있다고 한다.
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