Swift-서브 클래스에 의해 재정의되어야하는 클래스 메소드


91

Swift에서 "순수한 가상 기능"을 만드는 표준 방법이 있습니까? 일 해야한다 , 그렇지 않은 경우, 컴파일 시간 오류가 발생합니다 모든 서브 클래스를 오버라이드 (override) 할, 그리고?


슈퍼 클래스에서 구현하고 어설 션을 만들 수 있습니다. Obj-C, Java 및 Python에서 사용되는 것을 보았습니다.
David Skrundz 2014-06-08

8
@NSArray 이는 런타임이 아닌 컴파일시 에러가 발생
JuJoDi

이 답변은 당신에게도 도움이 될 것입니다. 여기 링크 설명을 입력
Chamath 지반에게

순수 가상 함수는 protocols에 의해 구현됩니다 ( interfaceJava의 s 와 비교 ) 추상 메서드처럼 사용해야하는 경우 다음 질문 / 답변을 참조하십시오. stackoverflow.com/a/39038828/2435872
jboi

답변:


147

두 가지 옵션이 있습니다.

1. 프로토콜 사용

수퍼 클래스를 클래스 대신 프로토콜로 정의

장점 : 각 "하위 클래스"(실제 하위 클래스가 아님)가 필요한 메서드를 구현하는지 컴파일 시간 확인

단점 : "수퍼 클래스"(프로토콜)는 메서드 나 속성을 구현할 수 없습니다.

2. 메서드의 슈퍼 버전에서 어설 션

예:

class SuperClass {
    func someFunc() {
        fatalError("Must Override")
    }
}

class Subclass : SuperClass {
    override func someFunc() {
    }
}

장점 : 수퍼 클래스에서 메서드 및 속성 구현 가능

단점 : 컴파일 시간 확인 없음


3
@jewirth 당신은 여전히 컴파일 타임 서브 클래스에 체크하지 것이다
drewag

5
프로토콜은 메서드를 구현할 수 없지만 대신 확장 메서드를 통해 제공 할 수 있습니다.
David Moles 2015 년

2
Swift 2.0에는 이제 프로토콜 확장도 있습니다. :) Apple Reference .
Ephemera

4
하지만 fatalError컴파일시 검사를 제공하지 않습니다, 그것은 컴파일러가 적어도 스마트 정도의 방법을 실행 경로 호출에 반환 값을 제공 할 필요가 없습니다 인 것이 좋다 fatalError.
bugloaf

3
사례 2 :super.someFunc() 재정의 된 메서드에서 호출 하면 재정의 했음에도 불구하고 오류가 발생한다는 사실에 유의하십시오. 당신은 당신이 그것을 부를 것이라고 생각하지 않는다는 것을 알고 있지만 다른 누군가는 그것을 알 필요가 없으며 표준 관행을 따르십시오.
Jakub Truhlář

48

다음은 클래스에서 상속하고 프로토콜의 컴파일 시간 검사를 허용합니다. :)

protocol ViewControllerProtocol {
    func setupViews()
    func setupConstraints()
}

typealias ViewController = ViewControllerClass & ViewControllerProtocol

class ViewControllerClass : UIViewController {

    override func viewDidLoad() {
        self.setup()
    }

    func setup() {
        guard let controller = self as? ViewController else {
            return
        }

        controller.setupViews()
        controller.setupConstraints()
    }

    //.... and implement methods related to UIViewController at will

}

class SubClass : ViewController {

    //-- in case these aren't here... an error will be presented
    func setupViews() { ... }
    func setupConstraints() { ... }

}

2
좋은 :) 구조에 typealias
크리스 Allinson

이 API 사용자가 ViewController 대신 ViewControllerClass에서 clild 클래스를 파생하지 못하도록하는 방법이 있습니까? 지금부터 몇 년 후 유형 별칭에서 파생 될 것이고 그때까지 어떤 함수를 재정의해야하는지 잊어 버릴 것이기 때문에 이것은 저에게 훌륭한 솔루션입니다.
David Rector

@David Rector, 수업을 비공개로하고 typealias를 공개 할 수 있습니까? 내 휴대 전화에서 메시지를 보내서 미안합니다. 확인할 수 없습니다.
ScottyBlades

1
완벽한 솔루션입니다. 감사합니다. @DavidRector에 의해 밑줄이 그어진 것처럼, typealias 만 공개되도록 만드는 솔루션이 있다면 좋을 것입니다.하지만 불행히도 불가능한 것 같습니다.
CyberDandy

35

추상 클래스 / 가상 함수에 대한 지원은 없지만 대부분의 경우 프로토콜을 사용할 수 있습니다.

protocol SomeProtocol {
    func someMethod()
}

class SomeClass: SomeProtocol {
    func someMethod() {}
}

SomeClass가 someMethod를 구현하지 않으면 다음 컴파일 시간 오류가 발생합니다.

error: type 'SomeClass' does not conform to protocol 'SomeProtocol'

30
이것은 프로토콜을 구현하는 최상위 클래스에서만 작동합니다. 모든 하위 클래스는 프로토콜 요구 사항을 가볍게 무시할 수 있습니다.
memmons

2
또한 프로토콜에서 제네릭을 사용하는 것은 지원되지 않습니다 = (
Dielson Sales

14

"가상"메서드가 너무 많지 않은 경우 다른 해결 방법은 하위 클래스가 "구현"을 기본 클래스 생성자에 함수 개체로 전달하도록하는 것입니다.

class MyVirtual {

    // 'Implementation' provided by subclass
    let fooImpl: (() -> String)

    // Delegates to 'implementation' provided by subclass
    func foo() -> String {
        return fooImpl()
    }

    init(fooImpl: (() -> String)) {
        self.fooImpl = fooImpl
    }
}

class MyImpl: MyVirtual {

    // 'Implementation' for super.foo()
    func myFoo() -> String {
        return "I am foo"
    }

    init() {
        // pass the 'implementation' to the superclass
        super.init(myFoo)
    }
}

1
당신은 몇 가지 더 많은 가상 방법이 있으면 그렇게 유용하지
Bushra 샤 히드

@ xs2bush 만약 당신의 메서드가 가상이 아닌 것보다 더 많은 경우 프로토콜에서 선언하고 확장 메서드를 통해 '비가 상'메서드를 제공하는 것이 더 낫습니다.
David Moles 2015 년

1
내가하고 결국 정확히 이잖아
Bushra 샤 히드

0

대답에 제안 당신은 주장 대 프로토콜을 사용할 수 있습니다 여기 에서 drewag. 그러나 프로토콜에 대한 예가 없습니다. 여기에서 다루고 있습니다.

실험 계획안

protocol SomeProtocol {
    func someMethod()
}

class SomeClass: SomeProtocol {
    func someMethod() {}
}

이제 컴파일 타임에 확인되는 프로토콜을 구현하기 위해 모든 하위 클래스가 필요합니다. SomeClass가 someMethod를 구현하지 않으면 다음 컴파일 시간 오류가 발생합니다.

오류 : 'SomeClass'유형이 'SomeProtocol'프로토콜을 따르지 않습니다.

참고 : 이것은 프로토콜을 구현하는 최상위 클래스에서만 작동합니다. 모든 하위 클래스는 프로토콜 요구 사항을 가볍게 무시할 수 있습니다. – 댓글memmons

역설

class SuperClass {
    func someFunc() {
        fatalError("Must Override")
    }
}

class Subclass : SuperClass {
    override func someFunc() {
    }
}

그러나 어설 션은 런타임에서만 작동합니다.


-2

iOS 개발을 처음 접했기 때문에 이것이 언제 구현되었는지 확실하지 않지만 두 세계를 최대한 활용하는 한 가지 방법은 프로토콜 확장을 구현하는 것입니다.

protocol ThingsToDo {
    func doThingOne()
}

extension ThingsToDo {
    func doThingTwo() { /* Define code here */}
}

class Person: ThingsToDo {
    func doThingOne() {
        // Already defined in extension
        doThingTwo()
        // Rest of code
    }
}

확장은 함수에 대한 기본값을 가질 수있게 해주는 반면 정규 프로토콜의 함수는 정의되지 않은 경우에도 컴파일 시간 오류를 제공합니다.


1
추상적 인 기능이 기본 구현의 반대
Hogdotmac
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.