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.