Go to a type with a common Swift extension, or ideally output it

Say what you have

class Fancy:UIView 

You want to find all sibling fancy views. No problem ...

  for v:UIView in superview!.subviews { if let f = v as? Fancy { f.hungry = false } } 

So try the extension,

 public extension UIView { internal func fancySiblings()->([Fancy]) { return (self.superview! .subviews .filter { $0 != self } .flatMap { $0 as? Fancy } ) } } 

Amazing you can now

  for f:Fancy in self.fancySiblings() { f.hungry = false } 

Fantastic.

But,

How to generalize this extension to work with any subtype of UIView?

Ideally, can an extension infer a type, even? Like the type?

So, something like ...

 public extension UIView { internal func siblings<T>( something T )->([T]) { return (self.superview! .subviews .filter { $0 != self } .flatMap { $0 as? T } ) } 

and then you could call it something like this ...

  for f in self.siblings(Fancy) for p in self.siblings(Prancy) for b in self.siblings(UIButton) 

How can you β€œtalk” about the general type extension that is used, for example?

It seems you can "pull it back",

 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() 

Which is surprising, but does not work differently.

You can even ...

  self.siblings().forEach{ (f:Fancy) in d.hasRingOn = false } 

Therefore, I would still like to know how to "pass" a type similar to for f in self.siblings(Fancy) , and, ideally, even output it as well.

+18
generics ios functional-programming swift swift-extensions
May 15 '16 at 15:25
source share
2 answers

Just use .Type :

 internal func siblings<T>( something : T.Type)->([T]) { ... } 

Then for f in self.siblings(Fancy) should work exactly as expected.

Full working example:

 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)) 

Correctly displays one view of Fancy !




To request an add-on for optional use of an explicit type parameter or to take effect of compiler type inference. You can create a second method in one extension

 internal func siblings<T>()->([T]) { return siblings(T) } 

Thus, providing an explicit type of parameters, calling the method one, omitting it will require you to make it inferable and will call the second function, which in terms of calls the first inside.




Or , you can use a much faster way and make an explicit type argument optional by default nil . This, admirably, will lead to the conclusion in the event of the exception of an argument of the type

 // 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 } ) } 

This will allow you to call the method either through

 for f in self.siblings(Fancy) 

or even

 for f : Fancy in self.siblings() 

Both will work while only defining one function.

+18
May 15 '16 at 15:32
source share

A similar answer to what was said earlier, but a little more ordered and without the need to skip something or iterate over subzones more than once:

 extension UIView { internal func siblings<T: UIView>() -> [T] { return superview?.subviews.flatMap {return ($0 == self) ? nil : ($0 as? T) } ?? [] } } 

or my preferences using options:

 internal func siblings<T: UIView>() -> [T]? { return superview?.subviews.flatMap {return ($0 == self) ? nil : $0 as? T } } 

Usage example:

 class ExampleView: UIView { func getMatchingSiblings(){ let foundSiblings: [ExampleView] = siblings() } //or with the for loop in the question: for item: ExampleView in siblings() { } } 

When working with generics, you just need one instance of the type type in the method signature. Therefore, if you have either a parameter or a return type that uses a common type, you do not need to pass this type.

+2
Aug 4 '16 at 20:21
source share



All Articles