swift - multiple - ¿Cómo puedo llamar a una función estática en un protocolo de una manera genérica?
protocolos swift (6)
¿Hay algún punto para declarar una función estática en un protocolo? El cliente que usa el protocolo tiene que llamar a la función en un tipo que se ajuste al protocolo, ¿no? Eso rompe la idea de no tener que conocer el tipo conforme al protocolo IMO. ¿Hay alguna forma de llamar a la función estática en el protocolo de una manera en que no tenga que saber el tipo real que se ajusta a mi protocolo?
Buena pregunta. Aquí está mi humilde punto de vista:
¿Hay algún punto para declarar una función estática en un protocolo?
Más o menos lo mismo que tener métodos de instancia declarados en un protocolo.
El cliente que usa el protocolo tiene que llamar a la función en un tipo que se ajuste al protocolo, ¿no?
Sí, exactamente como funciones de instancia.
Eso rompe la idea de no tener que conocer el tipo conforme al protocolo IMO.
No Mira el siguiente código:
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()
No sé el tipo real dentro de la variable feline
. Solo sé que se ajusta a Feline
. Sin embargo estoy invocando un método de protocolo estático.
¿Hay una mejor manera de hacer esto?
Ya veo, le gustaría llamar a un método / función estática declarada en un protocolo sin crear un valor que se ajuste al protocolo.
Algo como esto:
Feline.createRandomFeline() // DANGER: compiler is not happy now
Sinceramente, no sé la razón por la que esto no es posible.
Esto no es tanto una respuesta como una extensión de la pregunta. Di que tengo:
@objc public protocol InteractivelyNameable: Nameable {
static func alertViewForNaming(completion:@escaping((_ success: Bool, _ didCancel: Bool, _ error: Error?) -> Void)) -> UIAlertController?
}
Y tengo un controlador de vista genérico que administra varios tipos (el tipo genérico es .fetchableObjectType ... básicamente NSFetchResult). Necesito verificar si un tipo de objeto específico se ajusta al protocolo y, si es así, invocarlo.
algo como:
// valid swift code
if self.dataSource.fetchableObjectType is InteractivelyNameable {
// not valid swift code
if let alert = (self.dataSource.fetchableObjectType as InteractivelyNameable).alertViewForNaming(....)
}
Gracias @appzYourLife por la ayuda! Tu respuesta inspiró mi respuesta.
@appzYourLife respondió a mi pregunta. Tenía un problema subyacente que estaba tratando de resolver y el siguiente código resuelve mi problema, así que publicaré esto aquí, tal vez ayude a alguien con mi misma pregunta subyacente:
protocol MyProtocol {
static func aStaticFunc()
}
class SomeClassThatUsesMyProtocolButDoesntConformToIt {
var myProtocolType: MyProtocol.Type
init(protocolType: MyProtocol.Type) {
myProtocolType = protocolType
}
func aFunction() {
myProtocolType.aStaticFunc()
}
}
Un poco tarde para la fiesta de esta.
Aquí está mi solución para "agregar" propiedades / funciones / tipos estáticos a un protocolo usando typealias
.
Por ejemplo:
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 }
}
Entonces puedes hacer esto en cualquier lugar en tu código:
func postNotification() {
let scope: Property.Scope = .all
NotificationCenter.post(name: Property.Notifications.propertyDidChange,
object: scope)
}
Usar protocolos como las interfaces de Java rara vez es una buena idea. Son metatipos, destinados a definir contratos, que es un tipo de cosas completamente diferente.
Dicho esto, solo para el punto de comprensión, encuentro la manera más simple y efectiva de crear el equivalente de un método de fábrica estático de un protocolo para escribir una función libre.
Debe contener el nombre del protocolo, con la esperanza de que evite los choques de nombres y mejore la capacidad de descubrimiento.
En otros idiomas, createP sería un miembro estático de P, llamado create y se llamaría P.create (...), lo que mejoraría drásticamente la capacidad de descubrimiento y garantizaría la prevención de choques de nombres.
Sin embargo, en Swift, esta no es una opción para los protocolos, por lo que si los protocolos se usan realmente por alguna razón como reemplazo de las interfaces, al menos incluir el nombre del protocolo en el nombre de la función es una solución fea que todavía es un poco mejor que nada.
PD: en caso de que el objetivo sea realmente lograr algo así como una jerarquía de herencia con estructuras, las enumeraciones de estilo sindical son la herramienta que debe servir para ese propósito :)
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
}
si esto es posible
Swift 3
protocol Thing {
static func genericFunction()
}
//... in another file
var things:[Thing] = []
for thing in things {
type(of: thing).genericFunction()
}