web-dev-qa-db-fra.com

Quelle est la différence entre un protocole étendu à partir d'AnyObject et un protocole de classe uniquement?

Cette déclaration

protocol SomeProtocol : AnyObject {
}

et cette déclaration

protocol SomeProtocol : class {
}

semblent faire en sorte que seules les classes puissent se conformer à ce protocole (c'est-à-dire que les instances du protocole sont des références à des objets), et n'ont pas d'autres effets.

Y a-t-il une différence entre eux? Faut-il préférer l'un à l'autre? Sinon, pourquoi y a-t-il deux façons de faire la même chose?

J'utilise la dernière version de Xcode 6.3.1.

57
user102008

Cela a été répondu par un officiel Swift dev (Slava_Pestov) sur le forums Swift . Voici le résumé:

  • Vous devez utiliser AnyObject (protocol SomeProtocol: AnyObject).

  • AnyObject et class sont équivalents. Il n'y a pas de différence.

  • class sera finalement déconseillé.
13
kgaidis

Concernant la réponse https://forums.Swift.org/t/class-only-protocols-class-vs-anyobject/11507/4 , cette réponse est déconseillée. Ces mots sont les mêmes maintenant.

[~ # ~] déconseillé [~ # ~]

Mise à jour: Après avoir consulté les pouvoirs en place , les deux définitions sont supposé pour être équivalentes, AnyObject étant utilisé comme remplaçant pendant class était en cours de finition. À l'avenir, ces derniers éviteront les premiers mais, pour l'instant, ils présentent quelques différences mineures.

La différence réside dans la sémantique de @objc déclarations. Avec AnyObject, on s'attend à ce que les classes conformes soient ou non des objets Objective-C appropriés, mais le langage les traite quand même comme tels (en ce que vous perdez parfois la répartition statique). La leçon à en tirer est que vous pouvez traiter un AnyObject et al. contrainte de protocole comme moyen de demander @objc fonctions membres comme indiqué dans l'exemple dans la documentation de AnyObject dans la STL:

import Foundation
class C {
     @objc func getCValue() -> Int { return 42 }
}

// If x has a method @objc getValue()->Int, call it and
// return the result.  Otherwise, return nil.
func getCValue1(x: AnyObject) -> Int? {
    if let f: ()->Int = x.getCValue { // <===
        return f()
    }
    return nil
}
 // A more idiomatic implementation using "optional chaining"
func getCValue2(x: AnyObject) -> Int? {
    return x.getCValue?() // <===
}
 // An implementation that assumes the required method is present
func getCValue3(x: AnyObject) -> Int { // <===
    return x.getCValue() // x.getCValue is implicitly unwrapped. // <===
}

Le même exemple tombe immédiatement si vous changez cela en un protocole dérivant class:

import Foundation

protocol SomeClass : class {}

class C : SomeClass {
    @objc func getCValue() -> Int { return 42 }
}

// If x has a method @objc getValue()->Int, call it and
// return the result.  Otherwise, return nil.
func getCValue1(x: SomeClass) -> Int? {
    if let f: ()->Int = x.getCValue { // <=== SomeClass has no member 'getCValue'
        return f()
    }
    return nil
}

// A more idiomatic implementation using "optional chaining"
func getCValue2(x: SomeClass) -> Int? {
    return x.getCValue?() // <=== SomeClass has no member 'getCValue'
}

// An implementation that assumes the required method is present
func getCValue3(x: SomeClass) -> Int { // <===
    return x.getCValue() // <=== SomeClass has no member 'getCValue'
}

Il semble donc que class soit une version plus conservatrice de AnyObject qui devrait être utilisée lorsque vous ne vous souciez que de la sémantique de référence et non des recherches de membres dynamiques ou du pontage Objective-C.

10
CodaFi

Dans le Guide du langage de programmation Swift pour les protocoles , sous la section Protocoles de classe uniquement . Il ne mentionnait que AnyObject, mais pas class.

Vous pouvez limiter l'adoption du protocole aux types de classe (et non aux structures ou énumérations) en ajoutant le protocole AnyObject à la liste d'héritage d'un protocole.

protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
    // class-only protocol definition goes here
}

Pour cette raison, je suggérerai d'utiliser AnyObject sur class pour un nouveau code ou un nouveau projet. À part ça, je ne vois aucune différence évidente entre eux.

5
Yuchen Zhong

AnyObject est un protocole auquel toutes les classes sont implicitement conformes ( source ). Je dirais donc qu'il n'y a pas de différence: vous pouvez utiliser l'une ou l'autre pour exiger une contrainte de classe.

4
József Vesza

Si vous ouvrez l'aide (alt-clic) dans Xcode 9 pour class sur une ligne telle que protocol P: class {}, tu auras typealias AnyObject.

Ainsi, le code compilé (dans Swift 4) sera le même si vous contraignez le protocole à class ou AnyObject.

Cela dit, il y a aussi la question de style et options futures - un futur Swift pourrait vouloir traiter class et AnyObject différemment de façon subtile, même si ce n'est pas le cas actuellement.

0
idrougge

J'ai mal parlé avant. @MartinR devrait vraiment répondre à cette question, car c'est lui qui m'a corrigé et a fourni les informations correctes.

La différence réelle est qu'un protocole avec le qualificatif de classe ne peut être appliqué qu'à une classe, pas une structure ou une énumération.

Martin, pourquoi ne réponds-tu pas et le PO peut accepter ta réponse?

0
Duncan C