Remember that UIColor
is a class. A class is kind of like a blueprint that you use to create instances or objects that conform to that class. UIColor.red
is an example of an instance of the UIColor
class.
When you define a func
inside a class (in your case, as an extension), Swift assumes that you want to add that func
to the blueprint, which will in turn be available in all instances of the UIColor
class, like UIColor.red
.
You could also define your func
outside of all classes, by just placing it on the top level of the module, instead of inside an extension
.
However, to keep your functions organized, you can place functions like that inside the class name. You just have to tell Swift that you're not trying to add the function to the blueprint that will be applied to all instances, and that all you want instead is to have a function whose name is prefixed with the name of the class.
Here's an example to illustrate the difference in usage:
class Test {
func notStatic() {
print("called from an instance")
}
static func thisIsStatic() {
print("called on class name directly")
}
}
let instance = Test() // this is an *instance* of Test
instance.notStatic() // we can call a non static func on instance
Test.thisIsStatic() // we can call a static func directly on the class only
Now, let's go back to your specific example for a second. Notice that in your example, you're starting with a instance of Card.Colour
and trying to create a new instance of UIColor
.
In other words, adding a func
to UIColor
instances (i.e., a non-static
or class
) is useless to you, because you don't have an instance of UIColor
yet.
The idiomatic way of creating a new instance of a class is using an initializer (init
). So you could turn your function into an initializer on UIColor like this:
extension UIColor {
convenience init(cardColour: Card.Colour) {
switch cardColour {
case .Red: self.init(cgColor: UIColor.red.cgColor)
case .Blue: self.init(cgColor: UIColor.blue.cgColor)
case .Green: self.init(cgColor: UIColor.green.cgColor)
}
}
}
Now you just call UIColor(cardColour: .Red)
to get what you want. Note that in the implementation, I'm converting UIColor.red
to cgColor
and back as a quick hack. Feel free to use the initializer you see fit on UIColor
for each case of Card.Colour
.
But there's another way, which I think is even more elegant. Since you already have an instance of Card.Colour
, you can extend Card.Colour
with a function that gives you the UIColor
corresponding to the instance. Within that function, you can refer to the Card.Colour
instance using the keyword self
.
Since you already have the Card.Colour
instance through self
, you don't need to pass any arguments to that function. This allows you to use a cool feature called computed properties to make the usage even nicer.
This is how you'd add such an extension to Card.Colour
:
extension Card.Colour {
var uiColor: UIColor {
switch self {
case .Red: return .red
case .Blue: return .blue
case .Green: return .green
}
}
}
And you can then get a UIColor
from a Card.Colour
like this Card.Colour.Red.uiColor
or mainColour.uiColor
, where mainColour
is of type Card.Colour
.
Finally, as Leo Dabus noted in a comment, Swift's naming conventions is that cases should start with a lowercase letter. You should be using Card.Colour.red
instead of Card.Colour.Red
, etc. Those conventions came out around Swift 3 time. It was common to capitalize case names before then.