Swift에서 저장된 속성 재정의


126

컴파일러가 저장된 속성을 다른 저장된 값으로 재정의하는 것을 허용하지 않는다는 것을 알았습니다 (이상하게 보입니다).

class Jedi {
    var lightSaberColor = "Blue"
}


class Sith: Jedi {
    override var lightSaberColor = "Red" // Cannot override with a stored property lightSaberColor
}

그러나 계산 된 속성으로이 작업을 수행 할 수 있습니다.

class Jedi {
    let lightSaberColor = "Blue"
}


class Sith: Jedi {
    override var lightSaberColor : String{return "Red"}

}

다른 가치를 부여 할 수없는 이유는 무엇입니까?

저장된 속성으로 재정의하는 것이 혐오스러운 일이고 계산 된 코셔로하는 이유는 무엇입니까? 그들은 무엇을 생각합니까?


답변:


82

다른 가치를 부여 할 수없는 이유는 무엇입니까?

상속 된 속성에 다른 값을 부여 할 수 있습니다. 해당 초기 값을 사용하는 생성자에서 속성을 초기화하고 파생 클래스에서 다른 값을 전달하면이 작업을 수행 할 수 있습니다.

class Jedi {
    // I made lightSaberColor read-only; you can make it writable if you prefer.
    let lightSaberColor : String
    init(_ lsc : String = "Blue") {
        lightSaberColor = lsc;
    }
}

class Sith : Jedi {
    init() {
        super.init("Red")
    }
}

let j1 = Jedi()
let j2 = Sith()

println(j1.lightSaberColor)
println(j2.lightSaberColor)

속성을 재정의하는 것은 새 값을 제공하는 것과는 다릅니다. 클래스에 다른 속성을 제공하는 것과 비슷합니다. 실제로는 계산 된 속성을 재정의 할 때 발생합니다. 기본 클래스의 속성 을 계산하는 코드는 파생 클래스의 해당 속성에 대한 재정의를 계산하는 코드 로 대체 됩니다.

실제 저장된 속성을 재정의 할 수 lightSaberColor있습니까? 즉, 다른 동작이 있습니까?

관찰자 외에 저장된 속성에는 동작이 없으므로 실제로 재정의 할 것이 없습니다. 위에 설명 된 메커니즘을 통해 속성에 다른 값을 부여 할 수 있습니다. 이것은 다른 구문으로 질문의 예가 ​​달성하려는 것을 정확히 수행합니다.


2
@MaxMacLeod 관찰자 외에 저장된 속성에는 동작이 없으므로 실제로 재정의 할 것이 없습니다. 그는 저장된 속성에 하위 클래스의 다른 값을 부여하고 싶었지만이를 달성하는 메커니즘에 대해 확신하지 못했습니다. 대답은 Swift에서 어떻게 할 수 있는지 설명합니다. 늦게 답장을 드려 죄송합니다. 귀하의 의견으로 인해 반대 투표를 유도하기에 충분한 혼란이 발생하는 것으로 보이므로 진행 상황을 설명하기로 결정했습니다.
— dasblinkenlight

55

나를 위해 귀하의 예제는 Swift 3.0.1에서 작동하지 않습니다.

놀이터에이 코드를 입력했습니다.

class Jedi {
    let lightsaberColor = "Blue"
}

class Sith: Jedi {
    override var lightsaberColor : String {
        return "Red"
    }
}

Xcode에서 컴파일 타임에 오류가 발생합니다.

변경 불가능한 'let'속성 'lightsaberColor'를 'var'의 getter로 재정의 할 수 없습니다.

아니요, 저장된 속성의 유형을 변경할 수 없습니다. Liskov Substitution Principle 은 수퍼 클래스가 필요한 곳에서 서브 클래스가 사용되도록 강제 합니다.

그러나이를로 변경 하여 계산 된 속성에 var추가하는 set경우 동일한 유형의 계산 된 속성으로 저장된 속성을 재정의 할 수 있습니다.

class Jedi {
    var lightsaberColor = "Blue"
}


class Sith: Jedi {
    override var lightsaberColor : String {
        get {
            return "Red"
        }
        set {
            // nothing, because only red is allowed
        }
    }
}

이것은 저장된 속성에서 계산 된 속성으로 전환하는 것이 합리적 일 수 있기 때문에 가능합니다.

그러나 저장된 var속성을 저장된 속성으로 재정의하는 var것은 의미가 없습니다. 속성 값만 변경할 수 있기 때문입니다.

그러나 저장된 속성을 저장된 속성으로 재정의 할 수는 없습니다.


나는 Sith가 Jedi라고 말하지 않을 것이다 :-P. 따라서 이것이 작동하지 않는다는 것이 분명합니다.


18
class SomeClass {
    var hello = "hello"
}
class ChildClass: SomeClass {
    override var hello: String {
        set {
            super.hello = newValue
        }
        get {
            return super.hello
        }    
    }
}

13
이 코드 스 니펫은 질문을 해결할 수 있지만 설명을 포함하면 게시물의 품질을 향상시키는 데 큰 도움이됩니다. 앞으로 독자를 위해 질문에 답하고 있으며, 해당 사용자는 코드 제안 이유를 모를 수 있습니다.
— DimaSan

15

속성에 다른 값을 지정하고 싶을 것입니다.

class Jedi {
    var lightSaberColor = "Blue"
}


class Sith: Jedi {
    override init() {
        super.init()
        self.lightSaberColor = "Red"
    }
}

9
위의 의견에 따라 동일하게 적용
— Max MacLeod

10

Swift 4의 경우 Apple 문서에서 :

상속 된 인스턴스 또는 유형 속성을 재정 의하여 해당 속성에 대한 고유 한 사용자 정의 getter 및 setter를 제공하거나 재정의 속성이 기본 속성 값이 변경 될 때 관찰 할 수 있도록 속성 관찰자를 추가 할 수 있습니다.


7

Swift에서는 안타깝게도 불가능합니다. 가장 좋은 대안은 다음과 같습니다.

class Jedi {
    private(set) var lightsaberColor = "Blue"
}


class Sith: Jedi {
    override var lightsaberColor : String {
        get {
            return "Red"
        }
    }
}

3

뷰 컨트롤러에 상수를 설정하는 데 동일한 문제가 발생했습니다.

인터페이스 빌더를 사용하여 뷰를 관리하기 init()때문에를 사용할 수 없으므로 해결 방법은 기본 및 상속 된 클래스 모두에서 읽기 전용 계산 변수를 사용한 것을 제외하고는 다른 답변과 유사했습니다.

class Jedi {
    var type: String {
        get { return "Blue" }
    }
}

class Sith: Jedi {
    override var type: String {
        get { return "Red" }
    }
}

3

Swift 5에서 그렇게하려고하면

변경 불가능한 'let'속성 'lightSaberColor'를 'var'의 getter로 재정의 할 수 없습니다.

가장 좋은 방법은 계산 된 속성으로 선언하는 것입니다.

이것은 우리가 get {}함수를 재정의하는 것처럼 작동 합니다.

class Base {
   var lightSaberColor: String { "base" }
}

class Red: Base {
   override var lightSaberColor: String { "red" }
}

2

Swift는 변수 재정의를 허용하지 않습니다. stored property대신 사용할 수 있습니다.computed property

class A {
    var property1 = "A: Stored Property 1"

    var property2: String {
        get {
            return "A: Computed Property 2"
        }
    }

    let property3 = "A: Constant Stored Property 3"

    //let can not be a computed property
    
    func foo() -> String {
        return "A: foo()"
    }
}

class B: A {

    //now it is a computed property
    override var property1: String {

        set { }
        get {
            return "B: overrode Stored Property 1"
        }
    }

    override var property2: String {
        get {
            return "B: overrode Computed Property 2"
        }
    }
    
    override func foo() -> String {
        return "B: foo()"
    }

    //let can not be overrode
}
func testPoly() {
    let a = A()
    
    XCTAssertEqual("A: Stored Property 1", a.property1)
    XCTAssertEqual("A: Computed Property 2", a.property2)
    
    XCTAssertEqual("A: foo()", a.foo())
    
    let b = B()
    XCTAssertEqual("B: overrode Stored Property 1", b.property1)
    XCTAssertEqual("B: overrode Computed Property 2", b.property2)
    
    XCTAssertEqual("B: foo()", b.foo())
    
    //B cast to A
    XCTAssertEqual("B: overrode Stored Property 1", (b as! A).property1)
    XCTAssertEqual("B: overrode Computed Property 2", (b as! A).property2)
    
    XCTAssertEqual("B: foo()", (b as! A).foo())
}

Java와 비교할 때 클래스 필드를 덮어 쓸 수없고 컴파일 타임 (효율적으로 실행)에 정의되어 있기 때문에 다형성을 지원하지 않는 것이 더 분명합니다. 변수 숨김 이라고합니다. [About] 읽기 / 지원이 어렵 기 때문에 사용하지 않는 것이 좋습니다.

[스위프트 속성]


1

함수를 사용하여 재정의 할 수도 있습니다. 직접적인 대답은 아니지만이 주제를 풍부하게 할 수 있습니다.)

클래스 A

override func viewDidLoad() {
    super.viewDidLoad()

    if shouldDoSmth() {
       // do
    }
}

public func shouldDoSmth() -> Bool {
    return true
}

클래스 B : A

public func shouldDoSmth() -> Bool {
    return false
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.