Apple/Swift

[iOS/Swift] 오버라이딩(Overriding) 이란? (2/2)

59date 2024. 8. 28. 16:04

지난번 포스팅에 이어서 오버라이딩(Overriding)을 설명해 보겠습니다.

 

지난 포스팅은 여기를 참고해주시면 됩니다.

 

 

속성 오버라이딩(Property Overriding)

 

계산 속성(Computed Property) 

먼저 계산 속성 오버라이딩에는 제약 조건이 존재합니다.

  • 읽기 전용 속성을 읽기/쓰기 속성으로 오버라이딩하는 것은 가능합니다. 부모 클래스에 읽기 전용 속성이 있는 경우, 자식 클래스에서 이 속성을 읽기/쓰기 속성으로 오버라이딩할 수 있습니다.
  • 읽기/쓰기 속성을 읽기 전용 속성으로 오버라이딩 하는 것은 불가능합니다. 부모 클래스에서 읽기/쓰기 속성이 있는 경우, 자식 클래스에서 이 속성을 읽기 전용으로 오버라이딩할 수 없습니다. Swift에서 이는 문법적으로 허용되지 않으며, 컴파일 오류가 발생합니다.

 

1. 읽기 전용 속성을 ->  읽기/쓰기 속성으로 오버라이딩

class Parent {
    var value: String {
        return "읽기 전용 속성"
    }
}

현재 Parent 클래스의 value 속성은 읽기 전용으로 정의되어 있습니다. 값을 읽을 수는 있지만 변경할 수는 없는 상태입니다.

 

class Child: Parent {
    override var value: String {
        get {
            return "자식 클래스에서 재정의된 값"
        }
        set {
            print("새 값: \(newValue)")
        }
    }
}

Child 클래스에서는 Parent 클래스의 value 속성을 override 하여, get 블록과 함께 set 블록을 추가했습니다. 이로 인해 value 속성은 읽기/쓰기 모두 가능한 속성으로 변경되었습니다.

 

let child = Child()
print(child.value)  // 출력: 자식 클래스에서 재정의된 값
child.value = "테스트"  // 출력: 새 값: 테스트

Parent 클래스에서는 value를 읽을 수만 있고, 값을 설정할 수는 없었습니다.

그러나 Child 클래스에서는 value 속성에 값을 설정할 수 있는 set 블록을 추가했습니다. 이로 인해 value에 새로운 값을 설정할 때 추가적인 동작을 수행할 수 있게 되었습니다.

 

 

2. 읽기/쓰기 속성을 -> 읽기 전용 속성으로 오버라이딩 (컴파일 오류)

class Parent {
    var value: String {
        get {
            return "읽기/쓰기 속성"
        }
        set {
            print("부모 클래스에서 설정된 값: \(newValue)")
        }
    }
}

Parent 클래스의 value 속성은 읽기/쓰기 속성입니다. 값을 설정할 때는 set 블록이 호출되어,

"부모 클래스에서 설정된 값: \(newValue)" 라는 메시지가 출력됩니다. 즉 이 속성은 값을 읽을 수도 있고, 새로운 값을 설정할 수도 있는 상태입니다.

 

class Child: Parent {
    override var value: String {  //Cannot override mutable property with read-only property 'value'
        return "읽기 전용으로 만들 수 없음"
    }
}

Child 클래스에서 이 속성을 읽기 전용 속성으로 오버라이딩하려고 하면 Swift 컴파일러는 오류를 발생시킵니다.

이는 부모 클래스의 읽기/쓰기 속성을 자식 클래스에서 읽기 전용으로 변경하는 것이 허용되지 않기 때문입니다.

 

에러 메시지를 살펴보면

Cannot override mutable property with read-only property 'value'

“읽기/쓰기 가능한 속성(mutable property)을 읽기 전용 속성(read-only property)으로 오버라이드할 수 없습니다.”

라고 해석할 수 있습니다.

 

읽기/쓰기 가능한 속성: 부모 클래스의 value 속성은 읽기도 할 수 있고 쓰기도 할 수 있습니다. 이 속성에는 값을 가져오는 get과 값을 설정하는 set 기능이 모두 포함되어 있습니다.

 

읽기 전용 속성: 자식 클래스에서 이 value 속성을 오버라이드하려고 할 때, 읽기만 할 수 있게 만들려고 했습니다. 즉, 값을 가져오는 get 기능만 제공하고, 값을 설정하는 set 기능은 없애려고 한 것입니다.

 

오류의 이유: 이미 부모 클래스에서는 value 속성을 읽기/쓰기 가능하게 만들어 두었기 때문에, 자식 클래스에서는 이 속성을 읽기만 가능하게 제한할 수 없습니다. Swift에서는 상속받은 속성의 권한을 줄이는 방식으로 오버라이드하는 것을 허용하지 않기 때문에, 이와 같은 오류가 발생합니다.

 

요약하자면, “부모 클래스에서 제공하는 읽기/쓰기 속성을 자식 클래스에서 읽기 전용으로 제한할 수 없기 때문에 오류가 발생합니다.”

 

 

마지막으로

속성 오버라이딩에서 주의해야 할 또 하나의 중요한 점은 superself를 혼동하여 발생하는 재귀 호출 오류입니다.

 

super와 self를 혼동하여 발생하는 재귀 호출 오류

속성 오버라이딩을 할 때, get과 set에서 super을 사용해야 하는 상황에서 실수로 self를 사용하는 경우, 동일한 속성이 반복적으로 호출되면서 무한 재귀 호출이 발생할 수 있습니다.

 

이 경우, 프로그램은 스택 오버플로우(Stack Overflow) 에러를 발생시키며 강제로 종료될 수 있습니다.

 

이러한 오류는 디버깅이 어려울 수 있으므로, superself의 사용에 주의해야 합니다.

 

class Parent {
    var value: String {
        get {
            return "부모 클래스 속성"
        }
        set {
            print("부모 클래스에서 설정된 값: \(newValue)")
        }
    }
}

class Child: Parent {
    override var value: String {
        get {
            return super.value  // 올바른 사용: 부모 클래스의 속성을 가져옴
        }
        set {
            self.value = newValue  // 오류 발생: 재귀 호출로 인해 스택 오버플로우
        }
    }
}

let child = Child()
child.value = "테스트"  // 프로그램이 무한 루프에 빠지게 됩니다.

 

위 코드에서 super을 사용했을 때, super.value는 부모 클래스의 value 속성에 접근하게 됩니다. 이를 통해 부모 클래스에서 정의한 get과 set 동작을 그대로 사용할 수 있게 됩니다.

 

하지만 self를 사용하게 된다면

child.value = "테스트"를 실행하면, set 블록에서 self.value = newValue가 호출됩니다. 

여기서 self.value는 다시 Child 클래스의 value 속성을 호출하게 되고, 이로 인해 다시 set 블록이 실행됩니다.

이 과정에서 무한히 반복되면서 재귀 호출이 발생하고, 결국 스택 오버플로우로 인해 프로그램이 중단됩니다.

 

 

오버라이딩을 하다보면 super을 self로 사용하는 실수를 자주 하게 됩니다.

그리고 이러한 실수 때문에 에러가 발생하면 찾기도 힘들어서 실수하지 않도록 합시다.

 


 

 

잘못된 내용 혹은 오타가 있거나 더 좋은 내용 피드백은 언제나 환영입니다 :)