ios - type - Pase un tipo a una extensión Swift genérica, o infórmelo idealmente
public extension swift (2)
Di que tienes
class Fancy:UIView
Usted quiere encontrar todas las vistas de Fancy
hermanos. No hay problema
for v:UIView in superview!.subviews
{
if let f = v as? Fancy
{ f.hungry = false }
}
Entonces, intente una extensión,
public extension UIView
{
internal func fancySiblings()->([Fancy])
{
return (self.superview!
.subviews
.filter { $0 != self }
.flatMap { $0 as? Fancy }
)
}
}
Impresionante, ahora puedes
for f:Fancy in self.fancySiblings()
{ f.hungry = false }
Fantástico.
Pero,
¿Cómo generalizar esa extensión para trabajar con cualquier subtipo UIView?
Idealmente, ¿puede la extensión inferir el tipo , incluso? ¿Así como tomar un tipo?
Entonces, algo como ...
public extension UIView
{
internal func siblings<T>( something T )->([T])
{
return (self.superview!
.subviews
.filter { $0 != self }
.flatMap { $0 as? T }
)
}
y entonces podrías llamarlo algo como esto ...
for f in self.siblings(Fancy)
for p in self.siblings(Prancy)
for b in self.siblings(UIButton)
¿Cómo puedes "decirle" a una extensión genérica el tipo de uso, así?
Parece que puedes "inferirlo al revés",
public extension UIView
{
internal func incredible<T>()->([T])
{
return (self.superview!
.subviews
.filter { $0 != self }
.flatMap { $0 as? T }
)
}
for f:Fancy in self.incredible()
for p:Prancy in self.incredible()
Lo cual es asombroso pero no funciona de otra manera.
Usted puede incluso...
self.siblings().forEach{
(f:Fancy) in
d.hasRingOn = false
}
Así que todavía me gustaría saber cómo "pasar" un tipo como for f in self.siblings(Fancy)
e, idealmente, incluso inferirlo.
Respuesta similar a lo que se ha dicho anteriormente, pero un poco más simplificado y sin tener que pasar nada o iterar las subvistas más de una vez:
extension UIView {
internal func siblings<T: UIView>() -> [T] {
return superview?.subviews.flatMap {return ($0 == self) ? nil : ($0 as? T) } ?? []
}
}
o mi preferencia usando opcionales:
internal func siblings<T: UIView>() -> [T]? {
return superview?.subviews.flatMap {return ($0 == self) ? nil : $0 as? T }
}
Ejemplo de uso:
class ExampleView: UIView {
func getMatchingSiblings(){
let foundSiblings: [ExampleView] = siblings()
}
//or with the for loop in the question:
for item: ExampleView in siblings() {
}
}
Cuando se trata de genéricos, simplemente necesita una instancia del tipo genérico en la firma del método. Por lo tanto, si tiene un parámetro o un tipo de retorno que usa el genérico, no necesita pasar el tipo.
Simplemente use el .Type
:
internal func siblings<T>( something : T.Type)->([T]) {
...
}
Luego for f in self.siblings(Fancy)
debería funcionar exactamente como se esperaba.
Ejemplo completo de trabajo:
class Fancy : UIView {}
public extension UIView {
internal func siblings<T>( _ : T.Type)->([T]) {
return (self.superview!
.subviews
.filter { $0 != self }
.flatMap { $0 as? T }
)
}
}
let superView = UIView()
let view = UIView()
superView.addSubview(view)
superView.addSubview(UIView())
superView.addSubview(Fancy())
print(view.siblings(Fancy))
Salidas correctamente la una vista de Fancy
!
Para abordar la adición solicitada para usar opcionalmente el parámetro de tipo explícito o hacer efecto la inferencia de tipo del compilador. Puedes crear un segundo método en la misma extensión.
internal func siblings<T>()->([T]) {
return siblings(T)
}
De esa manera, al proporcionar un tipo explícito, el parámetro llama al método uno, omitiéndolo requerirá que lo hagas inferable y llamará a la segunda función, que en términos de llamada llama a la primera internamente.
O bien , puede usar la forma mucho más rápida y hacer que el argumento de tipo explícito sea opcional con el valor predeterminado nil
. Eso, notablemente, forzará la inferencia en caso de omitir el argumento de tipo:
// power extension, it provides both infered or stated typing
internal func siblings<T>(_ : T.Type? = nil) -> ([T]) {
return (self.superview!
.subviews
.filter { $0 != self }
.flatMap { $0 as? T }
)
}
Eso te permitirá llamar al método a través de
for f in self.siblings(Fancy)
o incluso
for f : Fancy in self.siblings()
Ambos funcionarán mientras que solo definen una función.