Swift - alt sınıf tarafından geçersiz kılınması gereken sınıf yöntemi


91

Swift'de "saf sanal işlev" yapmanın standart bir yolu var mı? biri olmalı , eğer değilse, bir derleme zamanı hatası neden her alt sınıf ile geçersiz ve?


Bunu süper sınıfta uygulayabilir ve bir iddiada bulunabilirsiniz. Bunun Obj-C, Java ve Python'da kullanıldığını gördüm.
David Skrundz

8
@NSArray Bu, derleme zamanı değil, çalışma zamanına neden olur
JuJoDi

Bu cevap size de yardımcı olacaktır. bağlantı açıklamasını buraya girin
Chamath Jeevan

S tarafından gerçek bir sanal işlev uygulanır protocol( interfaceJava'daki s ile karşılaştırıldığında ) Bunları soyut yöntemler gibi kullanmanız gerekiyorsa şu soruya / cevaba bakın: stackoverflow.com/a/39038828/2435872
jboi

Yanıtlar:


153

İki seçeneğiniz var:

1. Bir Protokol Kullanın

Üst sınıfı bir Sınıf yerine Protokol olarak tanımlama

Pro : Her "alt sınıf" ın (gerçek bir alt sınıf değil) gerekli yöntemi (yöntemleri) uygulayıp uygulamadığını derleme zamanı kontrolü

Eksileri : "Üst sınıf" (protokol) yöntemleri veya özellikleri uygulayamaz

2. Yöntemin süper versiyonunda iddia edin

Misal:

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

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

Pro : Üst sınıfta yöntemler ve özellikler uygulayabilir

Con : Derleme zamanı kontrolü yok


3
@jewirth alt sınıflarda hala bir derleme süresi kontrolü
alamazsınız

6
Protokol yöntemleri uygulayamaz, ancak bunun yerine bunları genişletme yöntemleriyle sağlayabilirsiniz.
David Moles

2
Swift 2.0'dan itibaren artık protokol uzantıları da var :) Apple Reference .
Ephemera

4
İken fatalErrorderleme zamanı denetlemesi sağlamaz, bu derleyici az akıllı, yeterli uzunlukta en yöntemle icra yolu aramaları için bir dönüş değeri vermenizi gerektirmez olduğunu güzeldir fatalError.
bugloaf

3
Durum 2: Unutmayın, super.someFunc()geçersiz kılınan yöntemden çağırırsanız , onu geçersiz kılmanıza rağmen hatayı alırsınız. Onu çağırmanız gerekmediğini biliyorsunuz, ancak başka birinin bunu bilmesi ve sadece standart uygulamayı takip etmesi gerekmiyor.
Jakub Truhlář

52

Aşağıdakiler bir sınıftan miras almaya ve ayrıca protokolün derleme zamanı kontrolüne sahip olmaya izin verir :)

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
güzel, kurtarmaya tipalias :)
Chris Allinson

Bu API'nin kullanıcılarının clild sınıflarını ViewController yerine ViewControllerClass'tan türetmesini engellemenin herhangi bir yolu var mı? Bu benim için harika bir çözüm çünkü bundan birkaç yıl sonra tür takma adımdan türeteceğim ve o zamana kadar hangi işlevlerin geçersiz kılınması gerektiğini unutmuş olacağım.
David Rektör

1
@David Rector, sınıfınızı özel ve tiplerinizi herkese açık hale getirebiliyor musunuz? Telefonumdan üzgünüm, kendimi kontrol edemiyorum.
ScottyBlades

1
Mükemmel çözüm, bunun için teşekkürler. @DavidRector'ın da vurguladığı gibi, bunu yalnızca tip takma adların herkese açık olması için bir çözüm olsaydı harika olurdu, ancak maalesef mümkün görünmüyor.
CyberDandy

derleme zamanında hata veren güzel, en zarif çözüm!
Bruce

35

Soyut sınıf / sanal işlevler için herhangi bir destek yoktur, ancak çoğu durumda muhtemelen bir protokol kullanabilirsiniz:

protocol SomeProtocol {
    func someMethod()
}

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

SomeClass bazı Yöntemleri uygulamazsa, bu derleme zamanı hatasını alırsınız:

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

30
Bunun yalnızca protokolü uygulayan en üst sınıf için çalıştığını unutmayın. Herhangi bir alt sınıf, protokol gereksinimlerini hızlıca göz ardı edebilir.
2015

2
Ayrıca, protokollerde jenerik kullanımı desteklenmez = (
Dielson Sales

14

Çok fazla "sanal" yönteminiz yoksa başka bir geçici çözüm, alt sınıfın "uygulamaları" temel sınıf yapıcısına işlev nesneleri olarak geçirmesini sağlamaktır:

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
birkaç sanal yöntemin varsa o kadar kullanışlı değil
Bushra Shahid

@ xs2bush Yöntemlerinizden daha fazlası sanal ise, bunları bir protokolde bildirmeniz ve uzantı yöntemleriyle 'sanal olmayan' olanları sağlamanız muhtemelen daha iyidir.
David Moles

1
tam olarak ne yaptığım bu
Bushra Shahid

2

Burada yanıtta önerildiği gibi protokol vs onaylamayı kullanabilirsiniz .drewag . Ancak, protokol örneği eksik. Ben burayı koruyorum

Protokol

protocol SomeProtocol {
    func someMethod()
}

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

Artık her alt sınıfın derleme zamanında kontrol edilen protokolü uygulaması gerekmektedir. SomeClass bazı Yöntemleri uygulamazsa, bu derleme zamanı hatasını alırsınız:

hata: 'SomeClass' türü 'SomeProtocol' protokolüne uymuyor

Not: Bu yalnızca protokolü uygulayan en üst sınıf için çalışır. Herhangi bir alt sınıf, protokol gereksinimlerini hızlıca göz ardı edebilir. - olarak yorumladı tarafındanmemmons

İddia

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

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

Ancak, iddia yalnızca çalışma zamanında çalışacaktır.


-2

İOS geliştirmede yeni olduğum için, bunun ne zaman uygulandığından tam olarak emin değilim, ancak her iki dünyadan da en iyi şekilde yararlanmanın bir yolu, bir protokol için bir uzantı uygulamaktır:

protocol ThingsToDo {
    func doThingOne()
}

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

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

Uzantı, bir işlev için varsayılan değere sahip olmanıza izin verirken, normal protokoldeki işlev tanımlanmamışsa yine de bir derleme zamanı hatası sağlar.


1
soyut işlevler, varsayılan uygulamaların tersidir
Hogdotmac
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.