How can I extend typed Arrays in Swift?
For extending typed arrays with classes, the below works for me (Swift 2.2). For example, sorting a typed array:
class HighScoreEntry {
let score:Int
}
extension Array where Element == HighScoreEntry {
func sort() -> [HighScoreEntry] {
return sort { $0.score < $1.score }
}
}
Trying to do this with a struct or typealias will give an error:
Type 'Element' constrained to a non-protocol type 'HighScoreEntry'
Update:
To extend typed arrays with non-classes use the following approach:
typealias HighScoreEntry = (Int)
extension SequenceType where Generator.Element == HighScoreEntry {
func sort() -> [HighScoreEntry] {
return sort { $0 < $1 }
}
}
In Swift 3 some types have been renamed:
extension Sequence where Iterator.Element == HighScoreEntry
{
// ...
}
Swift where Array Extensions
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
}
}
}
Array extension where Element is Optional and the the return type is Wrapped
I am not sure what you mean with Wrapped<Element>
but since you need to return something why not use a closure for the return value, like this function to get the element at a specific index
extension Array {
func value<T>(at index: Int, emptyAction: () -> T) -> T where Element == T? {
if let value = self[index] {
return value
}
return emptyAction()
}
}
Example
var test = [String?]()
test.append("ABC")
test.append("DEF")
test.append(nil)
for i in 0..<test.count {
print(test.value(at: i, emptyAction: { "<empty>" }))
}
Outputs
ABC
DEF
<empty>
Applying superclass array extensions to arrays of subclass instances
Use :
rather than ==
to mean "a subtype of":
class Superclass {
}
class Subclass : Superclass {
}
// here!
extension Array where Element: Superclass {
func f() {}
}
let a = [Subclass]()
a.f() // compiles!
Extension on Array where element is a generic struct in Swift
You will need to create a protocol with an associated type:
protocol MyGenericStructProtocol {
associatedtype GenericParameter
}
Let your struct adopt the protocol, either directly, or using an extension:
extension MyStruct: MyGenericStructProtocol {
typealias GenericParameter = T
}
Now you can reference the generic type inside your extension of Array:
extension Array where Element: MyGenericStructProtocol {
func doWork() -> [Element.GenericParameter] {
return []
}
}
Check out a fully working example on this GitHub gist
Array extension for finding index of custom type
You can extend Array and create a generic method to return the first index where the element is of an specific type:
extension Array {
func index<T>(with type: T.Type) -> Index? {
return index { $0 is T }
}
}
struct Fruit { }
let objects: [Any] = [1,2,Fruit(),"leedex"]
objects.index(with: Fruit.self) // 2
Swift Array extension with generic items
Try this:
import Foundation
protocol Section {
associatedtype InfoT: Equatable
associatedtype ItemsT: Equatable
var info: InfoT? { get }
var items: [ItemsT] { get }
}
extension Array where Element: Section {
// Just dummy example function:
func debugDummy() {
for section in self {
let info = section.info
print("section info: \(String(describing: info)).")
for item in section.items {
print("item: \(item).")
}
}
}
}
Extend array types using where clause in Swift
If you want to extend only array with specific type. You should extend _ArrayType protocol.
extension _ArrayType where Generator.Element == Int {
func doSomething() {
...
}
}
If you extend Array
you can only make sure your element is conformed some protocol else. i.e:
extension Array where Element: Equatable {
func doSomething() {
...
}
}
Updated:
With Swift 3.1 https://github.com/apple/swift/blob/master/CHANGELOG.md
extension Array where Element == Int {
func doSomething() {
...
}
}
Swift: Extension on [ SomeType T ?] to produce [ T ?] possible?
I don't know if there is a simpler solution now, but you can use the same “trick” as in How can I write a function that will unwrap a generic property in swift assuming it is an optional type? and Creating an extension to filter nils from an Array in Swift, the idea goes back to this Apple Forum Thread.
First define a protocol to which all optionals conform:
protocol OptionalType {
associatedtype Wrapped
var asOptional: Wrapped? { get }
}
extension Optional : OptionalType {
var asOptional: Wrapped? {
return self
}
}
Now the desired extension can be defined as
extension Collection where Element: OptionalType, Element.Wrapped: SomeTypeProtocol {
var values: [Element.Wrapped.NumberType?] {
return self.map( { $0.asOptional?.value })
}
}
and that works as expected:
let arr = [SomeType(value: 123), nil, SomeType(value: 456)]
let v = arr.values
print(v) // [Optional(123), Optional(456)]
print(type(of: v)) // Array<Optional<Int>>
Related Topics
Why Can't I Divide Integers in Swift
Firebase Says That My Rules Are Insecure, Why
How to Make Apple Sign in Revoke Token Post Request
Failed to Get Descriptors for Extensionbundleid
Round Top Corners of a Uiview in Swift
How to Block Users on Firebase in a Social Media App? for iOS
Get Header Data from a Request Response in Swift
How to Continue Ble Activities Onto Next View Controller
How to Open/View iOS Oslogs Stored on Device
Why Does Swift Provide Both a Cgrect Initializer and a Cgrectmake Function
Can Swift Playgrounds See Other Source Files in the Same Project
Detailed Instruction on Use of Nsopenpanel
Swift 3 Get Start Index (As Int) of Substring
Spritekit - Create at Random Position Without Overlapping