Quiero verificar si un tipo genérico se ajusta a un protocolo. Si es así, necesito emitir el tipo en sí y llamar a un método estático contra él.

func log<T>(object: T) {
    if let C = T as? Loggable {    // this line doesn't compile
        print("\(C.description(of: object))")
    } else {
        print("\(object)")
    }
}

Alguien sabe si es factible?

ACTUALIZACIÓN

Te confundí con mi primer fragmento de código. Con suerte, el segundo tiene más sentido. He realizado algunos cambios gracias a la respuesta de @ portella, pero aún no es suficiente.

func decodeObject<T>() -> T? {
    guard let object = objects.first else {
        return nil
    }
    objects.removeFirst()

    if object is NSNull {
        return nil
    }

    if T.self is Coding.Type {    // the condition is fixed, thanks to @Hiron
        if let data = object as? Data {
            return type(of: (T.self as! Coding)).from(data: data) as? T
        } else {
            return nil
        }
    }

    return object as? T
}
0
Artem Stepanenko 27 dic. 2016 a las 02:55

3 respuestas

La mejor respuesta

Digamos que tiene un protocolo con un método estático y una clase que lo implementa:

protocol Something {
    static func doSomething()
}

class SomethingConcrete: Something {
    static func doSomething() {
        // does something concrete
    }
}

También hay una función genérica. Si obtiene el tipo Something llama a su método estático (no hay ningún objeto involucrado).

Hay dos formas de hacerlo: sobrecarga y lanzamiento.

Sobrecarga (un crédito a @portella)

func someFunction<T: Something>() {
    T.doSomething()
}

func someFunction<T>() {
    // does something else
}

Casting (utiliza una verificación de tipo mencionada por @Hiron)

func someFunction<T>() {
    if T.self is Something.Type {
        (T.self as! Something.Type).doSomething()
    } else {
        // does something else
    }
}
0
Artem Stepanenko 29 dic. 2016 a las 09:43

¿Se ajusta esto a sus necesidades?

protocol Loggable {
    func log()
    static func staticLog()
}

func log<L: Loggable>(object: L) {
    object.log()
    L.staticLog()
}

Se asegura de que todos los objetos enviados a la función se ajusten al protocolo Loggable

Para mí, no me gusta esto, pero espero que la siguiente solución pueda ayudar ( fuertemente recomiendo la primera):

protocol Loggable {
    func log()
    static func staticLog()
}

func log<L>(object: L) {
    guard let loggableObject = object as? Loggable else {
        print("💩 Not a loggable object")

        return
    }

    loggableObject.log()
    type(of: loggableObject).staticLog()
}


final class NotLoggableClass {}

final class LoggableClass: Loggable {
    func log() {
        print("👏")
    }

    static func staticLog() {
        print("😕")
    }
}

log(object: NotLoggableClass())

log(object: LoggableClass())

La llamada log(object: NotLoggableClass()) regresará: 💩 Not a loggable object

La llamada log(object: LoggableClass()) regresará: 👏😕

EDITAR: con respecto a la actualización, ¿desea verificar el tipo de argumento o el tipo de argumento? No está enviando ningún argumento a su función, lo que parece extraño. Creo que le gustaría validarlo, no el retorno, supongo. ¿Es esto lo que estás tratando de lograr?

protocol Coding {
    associatedtype T

    static func decodeObject<T>(data: Data) -> T?
}

extension UIImage: Coding {
    typealias T = UIImage

    static func decodeObject<T>(data: Data) -> T? {
        return UIImage(data: data) as? T
    }
}

Con respecto a su solución, no entiendo el objects o de dónde vino. Si desea que el tipo genérico se ajuste a Coding protocol, puede hacerlo con una restricción en la declaración de la función.

Ejemplo:

protocol Coding {
    associatedtype T

    static func from(data: Data) -> T?
}

func decodeObject<T: Coding>(_ objects: [Data]) -> T? {
    guard let object = objects.first else {
        return nil
    }

    var objects = objects
    objects.removeFirst()

    return T.from(data: object) as? T
}

extension String: Coding {
    static func from(data: Data) -> String? {
        return String(data: data, encoding: .utf8)
    }
}

Aunque, no entiendo los objetos, esto debería ser algo que debe hacer el tipo en sí, no un ayudante común o algo que me parece lo que está intentando.

Intenta evitar el reparto dinámico y escribe con Swift 😉

Espero que ayude 🍻

1
portella 27 dic. 2016 a las 10:01

Quizás deberías escribir

if T.self is Coding.Type

En lugar de

if T.self is Coding
1
Hiron 27 dic. 2016 a las 02:58