Est-il utile de déclarer une fonction statique sur un protocole? Le client utilisant le protocole doit appeler la fonction sur un type conforme au protocole, n'est-ce pas? Cela rompt l’idée de ne pas avoir à connaître le type conforme au protocole OMI. Existe-t-il un moyen d'appeler la fonction statique sur le protocole de manière à ne pas avoir à connaître le type réel conforme à mon protocole?
Bonne question. Voici mon humble point de vue:
Quasiment pareil à avoir des méthodes d'instance déclarées dans un protocole.
Oui, exactement comme les fonctions d'instance.
Nan. Regardez le code suivant:
protocol Feline {
var name: String { get }
static func createRandomFeline() -> Feline
init()
}
extension Feline {
static func createRandomFeline() -> Feline {
return arc4random_uniform(2) > 0 ? Tiger() : Leopard()
}
}
class Tiger: Feline {
let name = "Tiger"
required init() {}
}
class Leopard: Feline {
let name = "Leopard"
required init() {}
}
let feline: Feline = arc4random_uniform(2) > 0 ? Tiger() : Leopard()
let anotherFeline = feline.dynamicType.createRandomFeline()
Je ne connais pas le type réel dans la variable feline
. Je sais juste que cela est conforme à Feline
. Cependant, j'appelle une méthode de protocole statique.
Je vois que vous voudriez appeler une méthode/fonction statique déclarée dans un protocole sans créer une valeur conforme au protocole.
Quelque chose comme ça:
Feline.createRandomFeline() // DANGER: compiler is not happy now
Honnêtement, je ne connais pas la raison pour laquelle ce n'est pas possible.
oui c'est possible:
Swift 3
protocol Thing {
static func genericFunction()
}
//... in another file
var things:[Thing] = []
for thing in things {
type(of: thing).genericFunction()
}
Merci @appzYourLife pour l'aide! Votre réponse a inspiré ma réponse.
@appzYourLife a répondu à ma question. J'avais un problème sous-jacent que j'essayais de résoudre et le code suivant résout mon problème. Je vais donc l'afficher ici, cela aidera peut-être quelqu'un qui a la même question sous-jacente:
protocol MyProtocol {
static func aStaticFunc()
}
class SomeClassThatUsesMyProtocolButDoesntConformToIt {
var myProtocolType: MyProtocol.Type
init(protocolType: MyProtocol.Type) {
myProtocolType = protocolType
}
func aFunction() {
myProtocolType.aStaticFunc()
}
}
Un peu tard pour la fête sur celui-ci.
Voici ma solution pour "ajouter" des propriétés/fonctions/types statiques à un protocole utilisant typealias
.
Par exemple:
enum PropertyScope {
case all
case none
}
struct PropertyNotifications {
static var propertyDidChange =
Notification.Name("propertyDidChangeNotification")
}
protocol Property {
typealias Scope = PropertyScope
typealias Notifications = PropertyNotifications
var scope: Scope { get set }
}
Ensuite, vous pouvez le faire n'importe où dans votre code:
func postNotification() {
let scope: Property.Scope = .all
NotificationCenter.post(name: Property.Notifications.propertyDidChange,
object: scope)
}
J'ai eu une situation où je dois créer le même objet DomainModel
à partir de 2
réponse différente. donc cette approche (la méthode static
dans protocol
m'a aidé) m'a aidée.
protocol BaseResponseKeyList: CodingKey {
static func getNameKey()->Self
}
enum FirstResponseKeyList: String, BaseResponseKeyList {
case name
func getNameKey()->FirstResponseKeyList {
return .name
}
}
enum SecondResponseKeyList: String, BaseResponseKeyList {
case userName
func getNameKey()->SecondResponseKeyList {
return .userName
}
}
struct MyDomainModel<T:BaseResponseKeyList> : Decodable {
var name:String?
required init(from d:Decoder) {
do {
let container = try d.container(keyedBy:T.self)
name = try container.decode(String.self, forKey:T.getNameKey())
}catch(_) {
print("error")
}
}
}
let myDomainModel = try JSONDecoder().decode(MyDomainModel <FirstResponseKeyList>.self, from: data)
let myDomainModel2 = try JSONDecoder().decode(MyDomainModel <SecondResponseKeyList>.self, from: data2)
L'utilisation de protocoles tels que les interfaces Java est rarement une bonne idée. Ce sont des méta-types, destinés à définir des contrats, ce qui est un genre complètement différent.
Cela étant dit, pour que tout soit clair, je trouve le moyen le plus simple et le plus efficace de créer l'équivalent d'une méthode de fabrique statique d'un protocole pour écrire une fonction libre.
Il devrait contenir le nom du protocole, en espérant que cela évitera les conflits de noms et améliorera la possibilité de découverte.
Dans d'autres langues, createP serait un membre statique de P, nommé create et s'appellerait P.create (...), ce qui améliorerait considérablement la possibilité de découverte et garantirait d'éviter les conflits de noms.
Toutefois, dans Swift, ce n'est pas une option pour les protocoles. Si, pour une raison quelconque, les protocoles sont réellement utilisés pour remplacer les interfaces, au moins, inclure le nom du protocole dans le nom de la fonction est une solution de contournement moche qui reste légèrement meilleure que rien.
P.S. si l'objectif est réellement de réaliser quelque chose comme une hiérarchie d'héritage avec des structures, les énumérations de style d'union sont l'outil qui est conçu pour atteindre cet objectif :)
protocol P
{
var x: Int { get }
}
func createP() -> P
{
if (todayIsMonday())
{
return A()
}
else
{
return B()
}
}
class A: P
{
var x = 5
}
class B: P
{
var x = 7
}
Ce n'est pas une réponse, c'est une extension de la question. Dis que j'ai:
@objc public protocol InteractivelyNameable: Nameable {
static func alertViewForNaming(completion:@escaping((_ success: Bool, _ didCancel: Bool, _ error: Error?) -> Void)) -> UIAlertController?
}
Et j'ai un contrôleur de vue générique qui gère divers types (le type générique est .fetchableObjectType ... essentiellement NSFetchResult). Je dois vérifier si un type d'objet spécifique est conforme au protocole et, le cas échéant, l'invoquer.
quelque chose comme:
// valid Swift code
if self.dataSource.fetchableObjectType is InteractivelyNameable {
// not valid Swift code
if let alert = (self.dataSource.fetchableObjectType as InteractivelyNameable).alertViewForNaming(....)
}