Conditionally Extending a Type - Swift 2.0, Xcode 7 and Interface Builder - iOS 9 Swift Programming Cookbook (2015)

iOS 9 Swift Programming Cookbook (2015)

Chapter 1. Swift 2.0, Xcode 7 and Interface Builder

1.12 Conditionally Extending a Type

Problem

You want to be able to extend existing data types that pass a certain test.

Solution

Use protocol extensions. Swift 2.0 allows protocol extensions to contain code.

Discussion

Let’ say that you want to add a method on any array in Swift where the items are integers. In your extension, you want to provide a method called canFind that can find a specific item in the array and return yes if it could be found. I know that we can do this with other system methods. I am offering this simple example to demonstrate how protocol extensions work.

extension SequenceType where

Generator.Element : IntegerArithmeticType{

public func canFind(value: Generator.Element) -> Bool{

for (_, v) in self.enumerate(){

if v == value{

return true

}

}

return false

}

}

Then you can go ahead and use this method like so:

func example1(){

if [1, 3, 5, 7].canFind(5){

print("Found it")

} else {

print("Could not find it")

}

}

As another example, let’s imagine that you want to extend all array types in Swift (SequenceType) that have items that are either double or floating point. It doesn’t matter which method you add to this extension. I am going to add an empty method for now:

extension SequenceType where Generator.Element : FloatingPointType{

//write your code here

func doSomething(){

//TODO: code this

}

}

And you can of course use it like so:

func example2(){

[1.1, 2.2, 3.3].doSomething()

}

However, if you try to call this method on an array that contains non-floating-point data, you will get a compilation error.

Let me show you another example. Let’s say that you want to extend all arrays that contain only strings, and you want to add a method to this array that can find the longest string. This is how we would do that:

extension SequenceType where Generator.Element : StringLiteralConvertible{

func longestString() -> String{

var s = ""

for (_, v) in self.enumerate(){

if let temp = v as? String

where temp.characters.count > s.characters.count{

s = temp

}

}

return s

}

}

Calling it is as simple as:

func example3(){

print(["Foo", "Bar", "Vandad"].longestString())

}

See Also