Est-ce possible dans Swift? Sinon, existe-t-il une solution de contournement pour le faire?
Est-ce possible dans Swift? Sinon, existe-t-il une solution de contournement pour le faire?
Réponses:
protocol MyProtocol {
func doSomething()
}
extension MyProtocol {
func doSomething() {
/* return a default value or just leave empty */
}
}
struct MyStruct: MyProtocol {
/* no compile error */
}
Les avantages
Aucun runtime Objective-C n'est impliqué (enfin, pas explicitement au moins). Cela signifie que vous pouvez lui conformer des structures, des énumérations et des non- NSObject
classes. En outre, cela signifie que vous pouvez profiter d'un puissant système générique.
Vous pouvez toujours être sûr que toutes les exigences sont remplies lorsque vous rencontrez des types conformes à ce protocole. C'est toujours une implémentation concrète ou une implémentation par défaut. C'est ainsi que les "interfaces" ou les "contrats" se comportent dans d'autres langues.
Désavantages
Pour les non- Void
exigences, vous devez avoir une valeur par défaut raisonnable , ce qui n'est pas toujours possible. Cependant, lorsque vous rencontrez ce problème, cela signifie que cette exigence ne devrait vraiment pas avoir d'implémentation par défaut, ou que vous vous êtes trompé lors de la conception de l'API.
Vous ne pouvez pas faire la distinction entre une implémentation par défaut et aucune implémentation , du moins sans résoudre ce problème avec des valeurs de retour spéciales. Prenons l'exemple suivant:
protocol SomeParserDelegate {
func validate(value: Any) -> Bool
}
Si vous fournissez une implémentation par défaut qui revient juste true
- c'est bien au premier coup d'œil. Maintenant, considérez le pseudo-code suivant:
final class SomeParser {
func parse(data: Data) -> [Any] {
if /* delegate.validate(value:) is not implemented */ {
/* parse very fast without validating */
} else {
/* parse and validate every value */
}
}
}
Il n'y a aucun moyen d'implémenter une telle optimisation - vous ne pouvez pas savoir si votre délégué implémente une méthode ou non.
Bien qu'il existe un certain nombre de façons différentes de résoudre ce problème (en utilisant des fermetures facultatives, différents objets délégués pour différentes opérations pour n'en nommer que quelques-uns), cet exemple présente clairement le problème.
@objc optional
.@objc protocol MyProtocol {
@objc optional func doSomething()
}
class MyClass: NSObject, MyProtocol {
/* no compile error */
}
Les avantages
Désavantages
Il limite considérablement les capacités de votre protocole en exigeant que tous les types conformes soient compatibles avec Objective-C. Cela signifie que seules les classes qui héritent de NSObject
peuvent se conformer à ce protocole. Pas de structures, pas d'énumérations, pas de types associés.
Vous devez toujours vérifier si une méthode facultative est implémentée en appelant ou en vérifiant éventuellement si le type conforme l'implémente. Cela peut introduire beaucoup de passe-partout si vous appelez souvent des méthodes facultatives.
respondsToSelector
?
optional func doSomething(param: Int?)
Dans Swift 2 et versions ultérieures, il est possible d'ajouter des implémentations par défaut d'un protocole. Cela crée une nouvelle façon de méthodes facultatives dans les protocoles.
protocol MyProtocol {
func doSomethingNonOptionalMethod()
func doSomethingOptionalMethod()
}
extension MyProtocol {
func doSomethingOptionalMethod(){
// leaving this empty
}
}
Ce n'est pas une très bonne façon de créer des méthodes de protocole facultatives, mais vous donne la possibilité d'utiliser des structures dans des rappels de protocole.
J'ai écrit un petit résumé ici: https://www.avanderlee.com/swift-2-0/optional-protocol-methods/
Puisqu'il y a quelques réponses sur la façon d'utiliser le modificateur facultatif et l' attribut @objc pour définir le protocole d'exigence facultatif, je vais donner un exemple sur la façon d'utiliser les extensions de protocole pour définir le protocole facultatif.
Le code ci-dessous est Swift 3. *.
/// Protocol has empty default implementation of the following methods making them optional to implement:
/// `cancel()`
protocol Cancelable {
/// default implementation is empty.
func cancel()
}
extension Cancelable {
func cancel() {}
}
class Plane: Cancelable {
//Since cancel() have default implementation, that is optional to class Plane
}
let plane = Plane()
plane.cancel()
// Print out *United Airlines can't cancelable*
Veuillez noter que les méthodes d'extension de protocole ne peuvent pas être invoquées par le code Objective-C, et pire encore, l'équipe Swift ne le réparera pas. https://bugs.swift.org/browse/SR-492
Les autres réponses ici impliquant le marquage du protocole comme "@objc" ne fonctionnent pas lors de l'utilisation de types spécifiques à Swift.
struct Info {
var height: Int
var weight: Int
}
@objc protocol Health {
func isInfoHealthy(info: Info) -> Bool
}
//Error "Method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C"
Afin de déclarer des protocoles facultatifs qui fonctionnent bien avec swift, déclarez les fonctions en tant que variables au lieu de func.
protocol Health {
var isInfoHealthy: (Info) -> (Bool)? { get set }
}
Et puis implémentez le protocole comme suit
class Human: Health {
var isInfoHealthy: (Info) -> (Bool)? = { info in
if info.weight < 200 && info.height > 72 {
return true
}
return false
}
//Or leave out the implementation and declare it as:
//var isInfoHealthy: (Info) -> (Bool)?
}
Vous pouvez ensuite utiliser "?" vérifier si la fonction a été implémentée ou non
func returnEntity() -> Health {
return Human()
}
var anEntity: Health = returnEntity()
var isHealthy = anEntity.isInfoHealthy(Info(height: 75, weight: 150))?
//"isHealthy" is true
Voici un exemple concret avec le modèle de délégation.
Configurez votre protocole:
@objc protocol MyProtocol:class
{
func requiredMethod()
optional func optionalMethod()
}
class MyClass: NSObject
{
weak var delegate:MyProtocol?
func callDelegate()
{
delegate?.requiredMethod()
delegate?.optionalMethod?()
}
}
Définissez le délégué sur une classe et implémentez le protocole. Vérifiez que la méthode facultative n'a pas besoin d'être implémentée.
class AnotherClass: NSObject, MyProtocol
{
init()
{
super.init()
let myInstance = MyClass()
myInstance.delegate = self
}
func requiredMethod()
{
}
}
Une chose importante est que la méthode facultative est facultative et nécessite un "?" lors de l'appel. Mentionnez le deuxième point d'interrogation.
delegate?.optionalMethod?()
Dans Swift 3.0
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
Cela vous fera gagner du temps.
@objc
est-elle nécessaire pour tous les membres maintenant?
required
flag, mais avec des erreurs: required
ne peut être utilisé que sur les déclarations 'init'.
optional
mot clé avant chaque méthode.@objc
, pas seulement le protocole.
Pour illustrer la mécanique de la réponse d'Antoine:
protocol SomeProtocol {
func aMethod()
}
extension SomeProtocol {
func aMethod() {
print("extensionImplementation")
}
}
class protocolImplementingObject: SomeProtocol {
}
class protocolImplementingMethodOverridingObject: SomeProtocol {
func aMethod() {
print("classImplementation")
}
}
let noOverride = protocolImplementingObject()
let override = protocolImplementingMethodOverridingObject()
noOverride.aMethod() //prints "extensionImplementation"
override.aMethod() //prints "classImplementation"
Je pense qu'avant de demander comment vous pouvez implémenter une méthode de protocole facultative, vous devriez vous demander pourquoi vous devriez en implémenter une.
Si nous considérons les protocoles rapides comme une interface dans la programmation orientée objet classique, les méthodes facultatives n'ont pas beaucoup de sens, et peut-être une meilleure solution serait de créer une implémentation par défaut, ou de séparer le protocole en un ensemble de protocoles (peut-être avec certaines relations d'héritage entre eux) pour représenter la combinaison possible de méthodes dans le protocole.
Pour plus de lecture, voir https://useyourloaf.com/blog/swift-optional-protocol-methods/ , qui donne un excellent aperçu de cette question.
Légèrement éloigné du sujet de la question d'origine, mais il se fonde sur l'idée d'Antoine et j'ai pensé que cela pourrait aider quelqu'un.
Vous pouvez également rendre les propriétés calculées facultatives pour les structures avec des extensions de protocole.
Vous pouvez rendre une propriété sur le protocole facultative
protocol SomeProtocol {
var required: String { get }
var optional: String? { get }
}
Implémenter la propriété calculée factice dans l'extension de protocole
extension SomeProtocol {
var optional: String? { return nil }
}
Et maintenant, vous pouvez utiliser des structures qui implémentent ou non la propriété facultative
struct ConformsWithoutOptional {
let required: String
}
struct ConformsWithOptional {
let required: String
let optional: String?
}
J'ai également écrit comment faire des propriétés facultatives dans les protocoles Swift sur mon blog , que je garderai à jour au cas où les choses changeraient avec les versions de Swift 2.
Comment créer des méthodes de délégué facultatives et obligatoires.
@objc protocol InterViewDelegate:class {
@objc optional func optfunc() // This is optional
func requiredfunc()// This is required
}
Voici un exemple très simple pour les classes rapides UNIQUEMENT, et non pour les structures ou les énumérations. Notez que la méthode de protocole étant facultative, a deux niveaux de chaînage facultatif en jeu. La classe adoptant le protocole a également besoin de l'attribut @objc dans sa déclaration.
@objc protocol CollectionOfDataDelegate{
optional func indexDidChange(index: Int)
}
@objc class RootView: CollectionOfDataDelegate{
var data = CollectionOfData()
init(){
data.delegate = self
data.indexIsNow()
}
func indexDidChange(index: Int) {
println("The index is currently: \(index)")
}
}
class CollectionOfData{
var index : Int?
weak var delegate : CollectionOfDataDelegate?
func indexIsNow(){
index = 23
delegate?.indexDidChange?(index!)
}
}
delegate?.indexDidChange?(index!)
:?
protocol CollectionOfDataDelegate{ func indexDidChange(index: Int) }
alors vous l'appelleriez sans le point d'interrogation: delegate?.indexDidChange(index!)
lorsque vous définissez une exigence facultative pour une méthode dans un protocole, le type qui s'y conformera pourrait ne PAS implémenter cette méthode , donc le ?
est utilisé pour vérifier l'implémentation et s'il n'y en a pas, le programme ne plantera pas. @Unheilig
weak var delegate : CollectionOfDataDelegate?
(assurer une référence faible?)
delegate?
utilisation à votre réponse? Cette information devrait vraiment appartenir à d'autres à l'avenir. Je veux voter positivement, mais cette information devrait vraiment être dans la réponse.
si vous voulez le faire en pure swift, le mieux est de fournir une implémentation par défaut si vous retournez un type Swift comme par exemple struct avec des types Swift
exemple :
struct magicDatas {
var damagePoints : Int?
var manaPoints : Int?
}
protocol magicCastDelegate {
func castFire() -> magicDatas
func castIce() -> magicDatas
}
extension magicCastDelegate {
func castFire() -> magicDatas {
return magicDatas()
}
func castIce() -> magicDatas {
return magicDatas()
}
}
alors vous pouvez implémenter un protocole sans définir chaque fonction
Il existe deux façons de créer une méthode facultative dans le protocole rapide.
1 - La première option consiste à marquer votre protocole à l'aide de l'attribut @objc. Bien que cela signifie qu'il ne peut être adopté que par des classes, cela signifie que vous marquez les méthodes individuelles comme étant facultatives comme ceci:
@objc protocol MyProtocol {
@objc optional func optionalMethod()
}
2 - Une manière plus rapide: cette option est meilleure. Écrivez des implémentations par défaut des méthodes facultatives qui ne font rien, comme ceci.
protocol MyProtocol {
func optionalMethod()
func notOptionalMethod()
}
extension MyProtocol {
func optionalMethod() {
//this is a empty implementation to allow this method to be optional
}
}
Swift a une fonctionnalité appelée extension qui nous permet de fournir une implémentation par défaut pour les méthodes que nous voulons être facultatives.
Une option consiste à les stocker en tant que variables de fonction facultatives:
struct MyAwesomeStruct {
var myWonderfulFunction : Optional<(Int) -> Int> = nil
}
let squareCalculator =
MyAwesomeStruct(myWonderfulFunction: { input in return input * input })
let thisShouldBeFour = squareCalculator.myWonderfulFunction!(2)
Définissez la fonction dans le protocole et créez l'extension pour ce protocole, puis créez une implémentation vide pour la fonction que vous souhaitez utiliser comme facultatif.
Pour définir Optional
Protocol
dans swift, vous devez utiliser le @objc
mot-clé before Protocol
declaration et attribute
/ method
declaration dans ce protocole. Voici un exemple de propriété facultative d'un protocole.
@objc protocol Protocol {
@objc optional var name:String?
}
class MyClass: Protocol {
// No error
}
Mettez le @optional
devant des méthodes ou des propriétés.
@optional
n'est même pas le bon mot-clé. C'est le cas optional
, et vous devez déclarer la classe et le protocole avec l' @objc
attribut.