2016-11-30 1 views
2

Je rencontre des problèmes pour essayer de limiter les exigences de type générique aux types de référence. Voici quelques exemples de code:Type de référence générique Swift

class WeakHolder<Element: AnyObject> { 
    weak var element: Element? 

    init(element: Element) { 
     self.element = element 
    } 
} 

protocol Animal: class { } 

class Dog: Animal { } 

let dog: Animal = Dog() 
let holder = WeakHolder<Animal>(element: dog) // Error: Using "Animal" as a concrete type conforming to protocol 'AnyObject' is not supported. 

Si je change l'exigence générique <Element: class>, je reçois l'erreur class constraint can only appear on protocol declarations.

Est-ce une limitation des génériques? Marquer un protocole comme une classe est suffisant pour avoir une faible référence à ce protocole, n'y at-il pas d'équivalent dans les génériques?

+0

Le chien n'est pas un AnyObject puisque Dog est un protocole –

+0

D'après ma petite expérience, cela pourrait être une limitation pour les génériques à partir de swift 2.3. Vous pouvez être en mesure de résoudre ce problème en utilisant des classes au lieu de protocoles –

+0

J'ai besoin d'utiliser des protocoles dans mon implémentation. – Mark

Répondre

0

La réponse simple est que vous ne pouvez pas avoir un type générique qui est un protocole.

En écrivant la syntaxe montre clairement comment cela fonctionne: class/struct GenericType<TypeName: TypeConstraints> {}

let thing = GenericType<Type>() where Type is a class or struct that adheres to any constraints

Un protocole exigeant l'adoption de types d'une classe signifie des adoptants sont des classes, mais le Protocole se est toujours pas un type.

Il est possible que les génériques puissent à un moment donné supporter les protocoles, mais cela nécessiterait de changer l'approche générale des protocoles ou des génériques. Bien que votre exemple spécifique puisse être possible avec une plus petite quantité de travail dans les coulisses, il est donc possible que cela puisse être implémenté à un moment donné.

Vous pouvez jeter un oeil à The Generics Manifesto si vous voulez voir la direction dans laquelle ils vont. L'écrémage Je n'ai rien trouvé de directement lié à votre cas d'utilisation, mais il est assez spécifique, donc il peut ne pas être inclus dans les paramètres du document.

+0

Ah, la contrainte de classe généralisée est exactement ce que je cherche. Bon à savoir que c'est envisagé pour une future version de Swift. – Mark

0

Une autre solution qui a fonctionné dans mon cas particulier est le suivant:

class WeakHolder<Element: AnyObject> { 
    weak var element: Element? 

    init(element: Element) { 
     self.element = element 
    } 
} 

protocol Animal: class { } 

class Dog: Animal { } 

let dog: Animal = Dog() 
let holder = WeakHolder<AnyObject>(element: dog as AnyObject) 

Lorsque accédant à l'élément, je dois simplement d'effectuer un retour baissés à mon protocole. Bien sûr, je perds la sécurité du temps de compilation lorsque j'utilise cette classe avec des types de valeur, mais ce n'est pas un problème dans ma situation.