As of Swift 2.0 it seems we can get closer to extensions of generic types applicable to predicated situations.
Although we still can't do this:
protocol Idable { var id : String { get } } extension Array where T : Idable { ... }
...we can now do this:
extension Array { func filterWithId<T where T : Idable>(id : String) -> [T] { ... } }
...and Swift grammatically accepts it. However, for the life of me I cannot figure out how to make the compiler happy when I fill in the contents of the example function. Suppose I were to be as explicit as possible:
extension Array { func filterWithId<T where T : Idable>(id : String) -> [T] { return self.filter { (item : T) -> Bool in return item.id == id } } }
...the compiler will not accept the closure provided to filter, complaining
Cannot invoke 'filter' with an argument list of type '((T) -> Bool)'
Similar if item is specified as Idable. Anyone had any luck here?
For example: var myArray = [Foo]() means that myArray will only contain type Foo . Foo in this case is "mapped" to the generic placeholder Element . If you want to change the general behavior of Array (via extension) you would use the generic placeholder Element and not any concrete type (like Foo).
Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you don't have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C.
You use the for-in loop to iterate over a sequence, such as items in an array. This example uses a for-in loop to iterate over the subviews and set their translatesAutoresizingMaskIntoConstraints to false . There also another variation of looping over a collection, that is forEach(_:) .
Only the instances of the subclass can use the new methods. Another diff : In extension, there is no any specific name of extension in swift, but while subclassing there is another name of subclass. In extension, we can not add variables (fields), in subclass it is possible to declare variables.
extension Array { func filterWithId<T where T : Idable>(id : String) -> [T] { ... } }
defines a generic method filterWithId()
where the generic placeholder T
is restricted to be Idable
. But that definition introduces a local placeholder T
which is completely unrelated to the array element type T
(and hides that in the scope of the method).
So you have not specified that the array elements must conform to Idable
, and that is the reason why you cannot call self.filter() { ... }
with a closure which expects the elements to be Idable
.
As of Swift 2 / Xcode 7 beta 2, you can define extension methods on a generic type which are more restrictive on the template (compare Array extension to remove object by value for a very similar issue):
extension Array where Element : Idable { func filterWithId(id : String) -> [Element] { return self.filter { (item) -> Bool in return item.id == id } } }
Alternatively, you can define a protocol extension method:
extension SequenceType where Generator.Element : Idable { func filterWithId(id : String) -> [Generator.Element] { return self.filter { (item) -> Bool in return item.id == id } } }
Then filterWithId()
is available to all types conforming to SequenceType
(in particular to Array
) if the sequence element type conforms to Idable
.
In Swift 3 this would be
extension Sequence where Iterator.Element : Idable { func filterWithId(id : String) -> [Iterator.Element] { return self.filter { (item) -> Bool in return item.id == id } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With