Swift: Propiedad conforme a una clase específica y al mismo tiempo a varios protocolos


En Objective-C, es posible escribir algo así:

@property(retain) UIView<Protocol1, Protocol2, ...> *myView;

Pero ¿cómo puedo escribir este código en swift?

Ya sé cómo hacer que una propiedad se ajuste a muchos protocolos, pero no funciona mediante el uso de la herencia:

var myView: ??? protocol<Protocol1, Protocol2, ...>

Editar:

Utilizo muchos UIView subtipos como UIImageView, UILabel u otros, y necesito usar algunas de las propiedades UIView más algunos métodos definidos en los protocolos. En el peor de los casos podría crear un UIViewProtocol con el propiedades necesarias, pero sabría si es posible en Swift declarar una propiedad/variable con un tipo y algún protocolo con el que conformarse.

Author: Binarian, 2014-09-10

3 answers

Puede hacer esto con una clase genérica usando una donde la cláusula :

Una cláusula where le permite requerir que un tipo asociado cumpla a un determinado protocolo, y / o que ciertos parámetros de tipo y los tipos asociados son los mismos.

Para usarlo, haga que la clase su propiedad esté definida en una clase genérica con una restricción de tipo para verificar si el parámetro de tipo para su propiedad coincide con la clase base deseada y protocolo.

Para su ejemplo específico, podría verse algo como esto:

class MyViewController<T where T: UIView, T: Protocol1, T: Protocol2>: UIViewController {
    var myView: T

    // ...
}
 24
Author: Mike S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-10 17:12:03

Una y probablemente un poco fea una de las formas de hacer eso, es crear un protocolo wrapper para UIView:

protocol UIViewRef {
    var instance: UIView { get }
}

Ahora es posible crear un protocolo que implemente Protocol1, Protocol2 y UIViewRef, que se va a utilizar para obtener el UIView en sí:

protocol MyUIViewProtocol: UIViewRef, Protocol1, Protocol2 { }

Y el último paso será implementar los protocolos UIViewRef para sus UIViews, que, en su caso, según entiendo, ya implementan Protocol1 y Protocol2:

// SomeOfMyViews already implements Protocol1 and Protocol2
extension SomeOfMyUIViews: MyUIViewProtocol {
    var instance: UIView { return self }
}

Como resultado tenemos MyUIViewProtocol, implementadores de los cuales mantener una referencia a un UIView y cada uno de ellos implementar Protocol1 y Protocol2. Sin embargo, una advertencia: para obtener el UIView en sí, necesitamos preguntar su referencia desde instance propiedad. Por ejemplo

// Lets say we're somewhere in a UIViewController
var views: [SomeOfMyUIView] = // Get list of my views
views.forEach { self.view.addSubview($0.instance) }
 5
Author: Slabko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-14 19:23:57

En Swift 4 es finalmente posible. Puede declarar variable de alguna clase conforme al protocolo al mismo tiempo, así:

class ClassA {
    var someVar: String?
}

protocol ProtocolA {}

class ClassB {
    var someOptional: (ClassA & ProtocolA)? // here is optional value
    var some: ClassA & ProtocolA // here is non-optional value; need to provide init though :)
}
 5
Author: Vladyslav Zavalykhatko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-21 13:21:24