신속한 언어로 추상 기능을 만들고 싶습니다. 가능합니까?
class BaseClass {
func abstractFunction() {
// How do I force this function to be overridden?
}
}
class SubClass : BaseClass {
override func abstractFunction() {
// Override
}
}
신속한 언어로 추상 기능을 만들고 싶습니다. 가능합니까?
class BaseClass {
func abstractFunction() {
// How do I force this function to be overridden?
}
}
class SubClass : BaseClass {
override func abstractFunction() {
// Override
}
}
답변:
Objective-C와 같은 Swift에는 추상 개념이 없지만 다음과 같이 할 수 있습니다.
class BaseClass {
func abstractFunction() {
preconditionFailure("This method must be overridden")
}
}
class SubClass : BaseClass {
override func abstractFunction() {
// Override
}
}
assert(false, "This method must be overriden by the subclass")
.
fatalError("This method must be overridden")
preconditionFailure("Bla bla bla")
Swift에는 릴리스 빌드에서 실행되며 return 문이 필요하지 않습니다. 편집 : 그냥이 방법은 기본적으로 같다는 것을 발견 fatalError()
하지만 더 적절한 방법 (더 나은 설명서와 함께 신속한 도입 precondition()
, assert()
그리고 assertionFailure()
읽기, 여기에 )
당신이 원하는 것은 기본 클래스가 아니라 프로토콜입니다.
protocol MyProtocol {
func abstractFunction()
}
class MyClass : MyProtocol {
func abstractFunction() {
}
}
클래스에 abstractFunction을 제공하지 않으면 오류입니다.
다른 행동을위한 기본 클래스가 여전히 필요한 경우 다음을 수행 할 수 있습니다.
class MyClass : BaseClass, MyProtocol {
func abstractFunction() {
}
}
추상 기본 클래스를 지원하는 플랫폼에서 Swift로 상당한 양의 코드를 이식하여이를 많이 실행합니다. 진정으로 원하는 것이 추상 기본 클래스의 기능이라면,이 클래스는 공유 기반 클래스 기능의 구현 역할을하며 (그렇지 않으면 인터페이스 / 프로토콜 일뿐) 다음에 의해 구현되어야하는 메소드를 정의합니다. 파생 클래스.
Swift에서 그렇게하려면 프로토콜과 기본 클래스가 필요합니다.
protocol Thing
{
func sharedFunction()
func abstractFunction()
}
class BaseThing
{
func sharedFunction()
{
println("All classes share this implementation")
}
}
기본 클래스는 공유 메소드를 구현하지만 프로토콜을 구현하지는 않습니다 (모든 메소드를 구현하지는 않기 때문에).
그런 다음 파생 클래스에서 :
class DerivedThing : BaseThing, Thing
{
func abstractFunction()
{
println("Derived classes implement this");
}
}
파생 클래스는 기본 클래스에서 sharedFunction을 상속하여 프로토콜의 해당 부분을 만족시키는 데 도움이되며 프로토콜은 여전히 파생 클래스가 abstractFunction을 구현해야합니다.
이 메소드의 유일한 단점은 기본 클래스가 프로토콜을 구현하지 않기 때문에 프로토콜 특성 / 메소드에 액세스해야하는 기본 클래스 메소드가있는 경우 파생 클래스의 메소드를 대체해야합니다. 기본 클래스가 (수퍼를 통해) 전달 self
하여 기본 클래스가 작업을 수행 할 프로토콜 인스턴스 를 갖도록합니다.
예를 들어, sharedFunction이 abstractFunction을 호출해야한다고 가정하십시오. 프로토콜은 동일하게 유지되며 클래스는 다음과 같습니다.
class BaseThing
{
func sharedFunction(thing: Thing)
{
println("All classes share this implementation")
thing.abstractFunction()
}
}
class DerivedThing : BaseThing, Thing
{
func sharedFunction()
{
super.sharedFunction(self)
}
func abstractFunction()
{
println("Derived classes implement this");
}
}
이제 파생 클래스의 sharedFunction은 프로토콜의 해당 부분을 만족하지만 파생 클래스는 여전히 기본 클래스 논리를 합리적으로 간단하게 공유 할 수 있습니다.
이것은 Apple이 UIKit에서 추상 메소드를 처리하는 방법의 "공식적인"방법 인 것 같습니다. UITableViewController
와 작동 방식을 살펴보십시오 UITableViewDelegate
. 가장 먼저하는 것 중 하나는 다음 줄을 추가하는 것 delegate = self
입니다. 글쎄, 그것은 정확히 속임수입니다.
protocol AbstractMethodsForClassX {
func abstractMethod() -> String
}
2. 기본 수업을 작성하십시오
/// It takes an implementation of the protocol as property (same like the delegate in UITableViewController does)
/// And does not implement the protocol as it does not implement the abstract methods. It has the abstract methods available in the `delegate`
class BaseClassX {
var delegate: AbstractMethodsForClassX!
func doSomethingWithAbstractMethod() -> String {
return delegate.abstractMethod() + " - And I believe it"
}
}
3. 서브 클래스를 작성하십시오.
/// First and only additional thing you have to do, you must set the "delegate" property
class ClassX: BaseClassX, AbstractMethodsForClassX {
override init() {
super.init()
delegate = self
}
func abstractMethod() -> String {return "Yes, this works!"}
}
여기에 모든 것을 사용하는 방법이 있습니다.
let x = ClassX()
x.doSomethingWithAbstractMethod()
출력을 보려면 놀이터를 확인하십시오.
UITableViewController
구현 UITableViewDelegate
하지만 여전히 대리자로 등록해야 delegate
합니다.getComments
부모 대리자에 대한 방법 이 있습니다 . 몇 가지 주석 유형이 있으며 각 객체와 관련된 주석 유형을 원합니다. 따라서 delegate.getComments()
해당 메서드를 재정의하지 않으면 하위 클래스가 컴파일되지 않기를 원합니다 . VC는 ParentDelegate
객체 delegate
또는 BaseClassX
예제에서 객체 가 있음을 알고 있지만 BaseClassX
추상화 된 메소드는 없습니다. 을 사용하고 있음을 구체적으로 알기 위해서는 VC가 필요합니다 SubclassedDelegate
.
이 작업을 수행하는 한 가지 방법은 기본 클래스에 정의 된 선택적 클로저를 사용하는 것이며 하위를 구현하도록 선택할 수 있습니다.
class BaseClass {
var abstractClosure?:(()->())?
func someFunc()
{
if let abstractClosure=abstractClosure
{
abstractClosure()
}
}
}
class SubClass : BaseClass {
init()
{
super.init()
abstractClosure={ ..... }
}
}
글쎄, 나는 게임에 늦었고, 일어난 변화를 이용하고 있다는 것을 알고있다. 미안합니다.
어쨌든 나는 테스트를 좋아하고 fatalError()
AFAIK 솔루션 은 테스트 할 수 없으며 예외가 있는 솔루션 은 테스트하기가 더 어렵 기 때문에 대답에 기여하고 싶습니다 .
더 빠른 접근 방식 을 사용하는 것이 좋습니다 . 귀하의 목표는 공통적 인 세부 사항을 가지고 있지만 완전히 정의되지 않은 추상화, 즉 추상 방법을 정의하는 것입니다. 추상화에서 예상되는 모든 메소드를 정의하는 프로토콜과 정의되지 않은 메소드를 모두 정의하는 프로토콜을 사용하십시오. 그런 다음 케이스에 정의 된 메소드를 구현하는 프로토콜 확장을 작성하십시오. 마지막으로 파생 클래스는 프로토콜을 구현해야합니다. 이는 모든 메서드를 의미하지만 프로토콜 확장의 일부인 메서드는 이미 구현되어 있습니다.
하나의 구체적인 함수로 예제를 확장하십시오.
protocol BaseAbstraction {
func abstractFunction() {
// How do I force this function to be overridden?
}
}
extension BaseAbstraction {
func definedFunction() {
print("Hello")
}
class SubClass : BaseAbstraction {
func abstractFunction() {
// No need to "Override". Just implement.
}
}
이렇게하면 컴파일러가 다시 친구가됩니다. 메소드가 "재정의되지 않은"경우 컴파일시 오류 fatalError()
가 발생하거나 런타임에 발생할 수있는 예외 대신 컴파일 오류 가 발생합니다.
나는 당신이 지금하고있는 일을 이해합니다. 프로토콜을 사용하는 것이 더 나을 것이라고 생각합니다
protocol BaseProtocol {
func abstractFunction()
}
그런 다음 프로토콜을 따르십시오.
class SubClass : BaseProtocol {
func abstractFunction() {
// Override
println("Override")
}
}
클래스가 서브 클래스 인 경우 프로토콜은 수퍼 클래스를 따릅니다.
class SubClass: SuperClass, ProtocolOne, ProtocolTwo {}
assert
키워드를 사용 하여 추상적 인 방법 시행 :
class Abstract
{
func doWork()
{
assert(false, "This method must be overriden by the subclass")
}
}
class Concrete : Abstract
{
override func doWork()
{
println("Did some work!")
}
}
let abstract = Abstract()
let concrete = Concrete()
abstract.doWork() // fails
concrete.doWork() // OK
그러나 Steve Waddicor가 언급했듯이 아마도 protocol
대신에 원할 것입니다.
나는 질문을 이해하고 동일한 해결책을 찾고있었습니다. 프로토콜은 추상 메소드와 다릅니다.
프로토콜에서 클래스가 해당 프로토콜을 준수하도록 지정해야합니다. 추상 메소드는 해당 메소드를 대체해야 함을 의미합니다.
즉, 프로토콜은 일종의 선택 사항이므로 기본 클래스와 프로토콜을 지정해야합니다 (프로토콜을 지정하지 않은 경우 해당 메소드를 재정의하지 않아도 됨).
추상 메소드는 기본 클래스를 원하지만 고유 한 메소드를 구현해야한다는 것을 의미합니다.
나는 같은 행동이 필요하기 때문에 해결책을 찾고 있습니다. Swift에는 그러한 기능이 없습니다.
@jaumard의 제안과 비교할 때 여전히 단점이 있지만이 문제에 대한 또 다른 대안이 있습니다. 리턴 문이 필요합니다. 나는 그것을 요구하는 요점을 그리워하지만 직접 예외를 던지기 때문에 구성됩니다.
class AbstractMethodException : NSException {
init() {
super.init(
name: "Called an abstract method",
reason: "All abstract methods must be overriden by subclasses",
userInfo: nil
);
}
}
그리고:
class BaseClass {
func abstractFunction() {
AbstractMethodException.raise();
}
}
그 이후에 오는 것은 무엇이든 도달 할 수 없기 때문에 나는 왜 돌아 오는 것을 보지 못합니다.
AbstractMethodException().raise()
합니까?
그것이 유용할지는 모르겠지만 SpritKit 게임을 빌드하는 동안 추상 메소드와 비슷한 문제가있었습니다. 내가 원했던 것은 move (), run () 등과 같은 메소드를 가진 추상 동물 클래스이지만 스프라이트 이름 (및 기타 기능)은 클래스 하위에서 제공해야합니다. 그래서 나는 이와 같은 일을 끝내 었습니다 (Swift 2에서 테스트 됨).
import SpriteKit
// --- Functions that must be implemented by child of Animal
public protocol InheritedAnimal
{
func walkSpriteNames() -> [String]
func runSpriteNames() -> [String]
}
// --- Abstract animal
public class Animal: SKNode
{
private let inheritedAnimal: InheritedAnimal
public init(inheritedAnimal: InheritedAnimal)
{
self.inheritedAnimal = inheritedAnimal
super.init()
}
public required init?(coder aDecoder: NSCoder)
{
fatalError("NSCoding not supported")
}
public func walk()
{
let sprites = inheritedAnimal.walkSpriteNames()
// create animation with walking sprites...
}
public func run()
{
let sprites = inheritedAnimal.runSpriteNames()
// create animation with running sprites
}
}
// --- Sheep
public class SheepAnimal: Animal
{
public required init?(coder aDecoder: NSCoder)
{
fatalError("NSCoding not supported")
}
public required init()
{
super.init(inheritedAnimal: InheritedAnimalImpl())
}
private class InheritedAnimalImpl: InheritedAnimal
{
init() {}
func walkSpriteNames() -> [String]
{
return ["sheep_step_01", "sheep_step_02", "sheep_step_03", "sheep_step_04"]
}
func runSpriteNames() -> [String]
{
return ["sheep_run_01", "sheep_run_02"]
}
}
}