web-dev-qa-db-fra.com

Protocoles de classe uniquement dans Swift

Je veux que certaines de mes classes (pas toutes) soient conformes en utilisant 'Class-Only Protocols' from docs. Ce que je fais c'est

protocol RefreshData: class, ClassA, ClassB
{
    func updateController()
}

et je reçois les erreurs

non class type 'RefreshData cannot inherit from classA
non class type 'RefreshData cannot inherit from classB

Je ne suis pas sûr de suivre exactement comme dans les documents. Quelqu'un a-t-il des idées à ce sujet?

30
tonytran

Swift 4 vous permet de combiner des types, vous pouvez donc avoir votre protocole, puis créer, par exemple, un alias de type pour le combiner avec une exigence de classe spécifique.

Pour (un exemple artificiel):

typealias PresentableVC = UIViewController & Presentable

Pour le code présenté:

Le problème est que vous essayez de vous limiter à des classes spécifiques et que Swift ne peut pas faire cela (pour le moment de toute façon). Vous pouvez uniquement limiter aux classes et hériter d'autres protocoles. Votre syntaxe est pour l'héritage de protocole mais vous essayez de l'utiliser comme limitation de classe.

Notez que le but des protocoles de classe est:

Utilisez un protocole de classe uniquement lorsque le comportement défini par les exigences de ce protocole suppose ou requiert qu'un type conforme ait une sémantique de référence plutôt qu'une valeur sémantique.

39
Wain

Les réponses fournies par Chris et Wain sont correctes. J'ajoute juste quelques détails supplémentaires ici.

Définition d'un protocole

Vous devez distinguer le concept de déclaration d'un protocol (disponible pour les classes)

protocol RefreshData: class {
    func updateController()
}

Définition d'une classe

... du concept de conformité de votre classe à un protocole

class ClassA: RefreshData {
    func updateController() {

    }
}

Conforme à une classe que vous ne possédez pas

Parfois, vous voulez conformer une classe à un protocole mais vous ne possédez pas le code source de cette classe. Dans ce cas, vous pouvez utiliser un extension

extension ClassB: RefreshData {
    func updateController() {

    }
}
21
Luca Angeletti

La dernière version de Swift peut le faire! Je ferais un protocole et des extensions de protocole qui ciblent les classes que vous voulez! (Contraignez l'extension à une classe spécifique)

    protocol Movable {
        func moveForward()
        func moveBackward()
    }

    extension Movable where Self: Car {
        func moveForward() {
            self.location.x += 10;
        }

        func moveBackward() {
            self.location.x -= 10;
        }
    }
    extension Movable where Self: Bike {
        func moveForward() {
            self.x += 1;
        }

        func moveBackward() {
            self.x -= 1;
        }
    }

    class Car: Movable {
        var location: CGPoint

        init(atLocation location: CGPoint) {
            self.location = location
        }
    }

    class Bike: Movable {
        var x: Int

        init(atX x: Int) {
            self.x = x
        }
}
9
AMTourky
protocol RefreshData : class
{
    func updateController()
}

class ClassA : RefreshData
{
    func updateController() {}
}

class ClassB : RefreshData
{
    func updateController() {}
}
3
Chris