Reputation: 660
I was trying to create an extension function on the UIColor which could take a parameter of type Card.Colour and return a UIColor back to the caller.
button.backgroundColor = UIColor.getColour(cardColour: cardToDeal.colour)
extension UIColor {
func getColour(cardColour: Card.Colour) -> UIColor {
switch cardColour {
case .Red:
return UIColor.red
case .Green:
return UIColor.green
case .Blue:
return UIColor.blue
}
}
}
When I tried to do this, the extension function of UIColor.getColour required me to enter a parameter of type UIColor rather than the specified type of Card.Colour in the extension method.
However, when I changed the extension function of getColour to either:
static func getColour(cardColour: Card.Colour) -> UIColor {
class func getColour(cardColour: Card.Colour) -> UIColor {
It allowed me to pass a parameter of type Card.Colour
Why is this? Why does changing the function to either a static function or a class function change the type required to be passed in?
Thanks in advance!
(A detailed answer would be much appreciated)
Upvotes: 3
Views: 1656
Reputation: 2678
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.
Upvotes: 8
Reputation: 510
An extension method operates on an instance of provided type. You can use all of the internal
properties and methods of an instance inside the method block.
static
methods are methods that are namespaced by the class name and do not operate on any specific instance of your class. class
methods are pretty much the same, just the difference between class
and static
is, that you can override
class
methods in a subclass.
Upvotes: 2