[inheritance] 스위프트 언어의 추상 클래스

Swift Language에서 추상 클래스를 만드는 방법이 있습니까, 아니면 Objective-C와 같은 제한입니까? Java가 추상 클래스로 정의한 것과 비슷한 추상 클래스를 만들고 싶습니다.



답변

Swift에는 Objective-C와 같은 추상 클래스가 없습니다. 최선의 방법은 Java 인터페이스와 같은 Protocol 을 사용하는 것 입니다.

Swift 2.0을 사용하면 프로토콜 확장을 사용하여 메소드 구현 및 계산 된 특성 구현을 추가 할 수 있습니다. 귀하의 유일한 제한은 당신이 것을있는 멤버 변수 나 상수를 제공 할 수 없습니다더 다이나믹 디스패치가 없습니다 .

이 기술의 예는 다음과 같습니다.

protocol Employee {
    var annualSalary: Int {get}
}

extension Employee {
    var biweeklySalary: Int {
        return self.annualSalary / 26
    }

    func logSalary() {
        print("$\(self.annualSalary) per year or $\(self.biweeklySalary) biweekly")
    }
}

struct SoftwareEngineer: Employee {
    var annualSalary: Int

    func logSalary() {
        print("overridden")
    }
}

let sarah = SoftwareEngineer(annualSalary: 100000)
sarah.logSalary() // prints: overridden
(sarah as Employee).logSalary() // prints: $100000 per year or $3846 biweekly

이것은 구조체에서도 “추상 클래스”기능을 제공하지만 클래스는 동일한 프로토콜을 구현할 수 있습니다.

또한 직원 프로토콜을 구현하는 모든 클래스 또는 구조체는 annualSalary 속성을 다시 선언해야합니다.

가장 중요한 것은 동적 디스패치가 없다는 것입니다 . 때 logSalaryA와 저장되어있는 인스턴스라고 SoftwareEngineer는 메소드의 오버라이드 (override) 버전을 호출합니다. 때 logSalary그가에 캐스팅 된 후 인스턴스라고 Employee, 그것은 인스턴스가 실제로 비록 그렇지 동적으로 오버라이드 (override) 버전으로 전달하지 않습니다 (원래 구현을 호출합니다 Software Engineer.

자세한 내용은 해당 기능에 대한 훌륭한 WWDC 비디오를 확인하십시오. Swift에서 가치 유형으로 더 나은 앱 구축


답변

이 답변은 Swift 2.0 이상을 대상으로합니다.

프로토콜 및 프로토콜 확장으로 동일한 동작을 수행 할 수 있습니다.

먼저, 준수하는 모든 유형으로 구현해야하는 모든 메소드에 대한 인터페이스 역할을하는 프로토콜을 작성하십시오.

protocol Drivable {
    var speed: Float { get set }
}

그런 다음이를 준수하는 모든 유형에 기본 동작을 추가 할 수 있습니다.

extension Drivable {
    func accelerate(by: Float) {
        speed += by
    }
}

이제를 구현하여 새 유형을 만들 수 있습니다 Drivable.

struct Car: Drivable {
    var speed: Float = 0.0
    init() {}
}

let c = Car()
c.accelerate(10)

기본적으로 다음을 얻습니다.

  1. 모든 Drivable구현 을 보장하는 컴파일 시간 확인speed
  2. Drivable( accelerate) 를 준수하는 모든 유형에 대해 기본 동작을 구현할 수 있습니다.
  3. Drivable 그것은 단지 프로토콜이기 때문에 인스턴스화되지 않도록 보장됩니다.

이 모델은 실제로는 특성과 훨씬 유사하게 작동하므로 여러 프로토콜을 준수하고 프로토콜의 기본 구현을 수행 할 수 있지만 추상 슈퍼 클래스에서는 간단한 클래스 계층 구조로 제한됩니다.


답변

나는 이것이 Java abstract또는 C #에 가장 가깝다고 생각합니다 abstract.

class AbstractClass {

    private init() {

    }
}

다음 사항을 참고 위해서는 private작업을 수정, 별도의 스위프트 파일에이 클래스를 정의해야합니다.

편집 : 여전히이 코드는 추상 메소드를 선언 할 수 없으므로 구현을 강제합니다.


답변

가장 간단한 방법은 fatalError("Not Implemented")프로토콜 확장에서 변수가 아닌 추상 메소드를 호출하는 것 입니다.

protocol MyInterface {
    func myMethod() -> String
}


extension MyInterface {

    func myMethod() -> String {
        fatalError("Not Implemented")
    }

}

class MyConcreteClass: MyInterface {

    func myMethod() -> String {
        return "The output"
    }

}

MyConcreteClass().myMethod()


답변

몇 주 동안 어려움을 겪은 후 마침내 Java / PHP 추상 클래스를 Swift로 변환하는 방법을 깨달았습니다.

public class AbstractClass: NSObject {

    internal override init(){}

    public func getFoodToEat()->String
    {
        if(self._iAmHungry())
        {
            return self._myFavoriteFood();
        }else{
            return "";
        }
    }

    private func _myFavoriteFood()->String
    {
        return "Sandwich";
    }

    internal func _iAmHungry()->Bool
    {
        fatalError(__FUNCTION__ + "Must be overridden");
        return false;
    }
}

public class ConcreteClass: AbstractClass, IConcreteClass {

    private var _hungry: Bool = false;

    public override init() {
        super.init();
    }

    public func starve()->Void
    {
        self._hungry = true;
    }

    public override func _iAmHungry()->Bool
    {
        return self._hungry;
    }
}

public protocol IConcreteClass
{
    func _iAmHungry()->Bool;
}

class ConcreteClassTest: XCTestCase {

    func testExample() {

        var concreteClass: ConcreteClass = ConcreteClass();

        XCTAssertEqual("", concreteClass.getFoodToEat());

        concreteClass.starve();

        XCTAssertEqual("Sandwich", concreteClass.getFoodToEat());
    }
}

그러나 Apple은 일반적으로 대리자 + 프로토콜 패턴을 대신 사용하기 때문에 추상 클래스를 구현하지 않았다고 생각합니다. 예를 들어 위와 동일한 패턴이 다음과 같이 더 잘 수행됩니다.

import UIKit

    public class GoldenSpoonChild
    {
        private var delegate: IStomach!;

        internal init(){}

        internal func setup(delegate: IStomach)
        {
            self.delegate = delegate;
        }

        public func getFoodToEat()->String
        {
            if(self.delegate.iAmHungry())
            {
                return self._myFavoriteFood();
            }else{
                return "";
            }
        }

        private func _myFavoriteFood()->String
        {
            return "Sandwich";
        }
    }

    public class Mother: GoldenSpoonChild, IStomach
    {

        private var _hungry: Bool = false;

        public override init()
        {
            super.init();
            super.setup(self);
        }

        public func makeFamilyHungry()->Void
        {
            self._hungry = true;
        }

        public func iAmHungry()->Bool
        {
            return self._hungry;
        }
    }

    protocol IStomach
    {
        func iAmHungry()->Bool;
    }

    class DelegateTest: XCTestCase {

        func testGetFood() {

            var concreteClass: Mother = Mother();

            XCTAssertEqual("", concreteClass.getFoodToEat());

            concreteClass.makeFamilyHungry();

            XCTAssertEqual("Sandwich", concreteClass.getFoodToEat());
        }
    }

viewWillAppear 등과 같은 UITableViewController의 일부 메소드를 일반화하고 싶기 때문에 이런 종류의 패턴이 필요했습니다.


답변

프로토콜을 사용하여 추상 클래스를 시뮬레이션하는 방법이 있습니다. 이것은 예입니다 :

protocol MyProtocol {
   func doIt()
}

class BaseClass {
    weak var myDelegate: MyProtocol?

    init() {
        ...
    }

    func myFunc() {
        ...
        self.myDelegate?.doIt()
        ...
    }
}

class ChildClass: BaseClass, MyProtocol {
    override init(){
        super.init()
        self.myDelegate = self
    }

    func doIt() {
        // Custom implementation
    }
}


답변

추상 클래스를 구현하는 또 다른 방법은 초기화 프로그램을 차단하는 것입니다. 나는 이렇게했다 :

class Element:CALayer { // IT'S ABSTRACT CLASS

    override init(){
        super.init()
        if self.dynamicType === Element.self {
        fatalError("Element is abstract class, do not try to create instance of this class")
        }
    }
}