ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • inout 파라미터 작동 방식 파해치기
    Apple🍎/Swift 2025. 3. 11. 22:21

    Swift에서 함수의 파라미터로 전달 된 값은 타입에 따라 다르게 동작하며,

    Inout 키워드를 통해 이 동작 방식을 변경할 수 있는데요. 

    오늘은 이에 대해 자세히 알아보도록 하겠습니다. 

    기본 파라미터 동작 방식 

    Swift에는 두 가지 주요 데이터 타입이 있죠? 

     

    값 타입 (Value Type) : Int, String 같은 기본 타입 또는 struct, enum 

    참조 타입(Reference Type) : class 

     

    값 타입은 스택에 저장되며 값을 넘겨 줄 때 원래 값을 복사를 하여 복사본을 넘겨주기 때문에 

    새로 넘겨 받은 곳에서 값을 변경해도 원래 값에는 영향이 가지 않습니다. 

     

    그에 비해 참조 타입은 힙에 저장되며 값을 넘겨 줄때 참조값(메모리 주소)를 넘겨주기 때문에 

    새로 넘겨 받은 곳에서도 같은 메모리를 참조하여 값을 변경하면 원래 값에에 영향이 갑니다. 

     

    위의 데이터 타입마다의 특징을 잘 기억해 두세용. 

    값 타입 파라미터 

    값 타입 파라미터는 복사되어 함수에 전달됩니다. 

    func modify(number: Int) {
        // number는 원본의 복사본
        var localNumber = number
        localNumber += 10
        // 원본 변수는 영향받지 않음
    }
    
    var myNumber = 5
    modify(number: myNumber)
    // myNumber는 여전히 5

    메인 함수에서 값(정수) 타입 myNumber 지역 변수를 선언한 다음 

    modify 함수를 호출할 때 해당 변수를 파라미터로 전달하면 

    myNumber의 값인 5가 modifiy의 number 파라미터에 복사가 되어 전달됩니다. 

    따라서 modifiy 함수 내부에서 number 값을 변경해도 

    원래 myNumber 변수에는 영향을 주지 않습니다. 

    참조 타입 파라미터

    참조 타입 파라미터는 참조의 복사본(메모리 주소)이 전달 됩니다. 

    class Person {
        var name: String
        
        init(name: String) {
            self.name = name
        }
    }
    
    func modify(person: Person) {
        // person은 원본 객체를 가리키는 참조의 복사본
        person.name = "변경된 이름"
        // 원본 객체가 변경됨
    }
    
    let myPerson = Person(name: "원래 이름")
    modify(person: myPerson)
    // myPerson.name은 "변경된 이름"으로 변경됨

    메인 함수에서 참조 타입인 Person 클래스의 인스턴스 myPerson을 생성한다음에 

    이를 modify 함수를 호출할 때 파라미터로 넘겨주면 

    myPerson의 참조값이 전달됩니다. 

    따라서 modify 함수 내부에서 person 파라미터에 접근해 값을 변경하면 

    원래 myPerson 변수의 name 프로퍼티 값도 동일하게 변경됩니다. 

     

    inout 파라미터 

    기본적으로 Swift의 파라미터는 함수 내에서 수정할 수 없지만, inout 를 사용하면 원본 변수를 직접 수정할 수 있습니다. 

     

    값 타입 파라미터 + inout 

    값 타입 파라미터에 inout 키워드를 사용하면 값을 복사하지 않고 원본 변수의 메모리 주소에 직접 접근합니다. 

    func modify(number: inout Int) {
        number += 10
        // 원본 변수가 수정됨
    }
    
    var myNumber = 5
    modify(number: &myNumber) // & 기호 필수
    // myNumber는 이제 15

    동작 과정을 좀더 상세히 살펴보면

    1. 함수 호출시, 원본 변수의 메모리 주소가 함수에 전달 됩니다. 

    2. 함수 내부에서는 그 주소를 통해 원본 값에 접근하고 수정합니다. 

    3. 함수가 반환될 때, 변경된 값이 원본 변수에 반영됩니다. 

     

    따라서 modify의 number 변수로 전달된 myNumber 변수는 함수 호출이 이후 값이 변경됩니다. 

     

    참조 타입 파라미터 + inout

    참조 타입에 inout 키워드를 사용하면 참조 자체를 변경할 수 있습니다. 

    ( 값 타입일 때 변수의 메모리 주소를 전달하는 것처럼 참조 타입의 경우에는 참조값(메모리 주소)이 들어 있는 메모리주소를 전달합니다.)

    그니까 원래는 메모리 주소 값을 전달했는데 이제는 메모리 주소 값이 들어있는 메모리 주소를 전달

    func replace(person: inout Person) {
        // person 참조 자체를 다른 객체로 대체
        person = Person(name: "완전히 새로운 사람")
    }
    
    var myPerson = Person(name: "원래 사람")
    replace(person: &myPerson)
    // myPerson은 이제 "완전히 새로운 사람"을 가리킴

    일반 참조 파라미터로는 전달된 메모리 주소 값을 통해 해당 주소에 있는 객체의 속성만 변경할 수 있지만,

    inout을 사용하면 참조 값을 저장하는 메모리 자체에 접근해서 해당 참조 값을 다른 참조 값으로 바꿔버릴 수 있습니다. 

     

    정리하면 아래와 같습니다. 

     

    값 타입에 inout을 사용하면 → 참조로 전달되어 원본이 수정됨

    참조 타입에 inout을 사용하면 → 참조의 참조가 전달됨 (포인터의 포인터 개념)


    inout: "복사해서 들어가고, 수정해서 나온다"

    댓글

Designed by Tistory.