We touched a bit on this in a previous post Classes In Swift — An Introduction. To recap what was mentioned in that post, methods are functions that are associated with a type. In other words, all methods are functions, but not all functions are methods. Functions can be written outside of the context of a type, especially in playgrounds. I felt it would be best to state that in a post dedicated to them, instead of having it just nestled in the Classes post. I also have learned of some nuances about them, that there are a few differences between them, particularly in parameter naming. While I’m at it, we’ll quickly cover the idea of type methods as well.
Instance Method External Parameter Name Nuance
To explain this better, we need a slight history lesson. In Objective-C, there are many instances where a method name would refer to the first parameter, and the next parameters would have labels describing them as the function call went on. Here is a particularly common function prototype like that:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Good ol’ tableView:didSelectRowAtIndexPath:. It’s not as common as cellForRowAtIndexPath:, but that one only takes one parameter, and this is something I wanted to show. You can see how the “name” of the function is “tableView”, and it refers to an object of the type (UITableView *), with an internal name of tableView. The next parameter has an external name “didSelectRowAtIndexPath:”, which takes an object of type (NSIndexPath *), with an internal name of “indexPath”.
While you would usually never call this function yourself (it is usually something you override when writing a UITableViewDelegate). Nonetheless, if you did call it, it would look something like this:
[self tableView:myTable didSelectRowAtIndexPath:myIndexPath]
Again, really, don’t call that yourself. Anyway, you can see how the parameter names make this read similar to a sentence. In this case you are telling the self object, that the tableView named myTable did have a row selected that is at an indexPath named “myIndexPath.”
So, what does this look like in Swift?
//Method Prototype func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) //Called someTableViewDelegate.tableView(myTable, didSelectRowAt: myIndexPath)
Okay, that isn’t too surprising, it had an external parameter name of didSelectRowAtIndexPath.
However, what if we delete that external parameter name, and just leave it with the internal parameter name:
//Method Prototype func tableView(tableView: UITableView, indexPath: NSIndexPath) //Called someTableViewDelegate.tableView(myTable, indexPath: myIndexPath)
Mutating Properties of Structures and Enumerations
If you recall, in our discussion about Protocols in Swift, if we wanted to change internal values for structures and enumerations, we had to preface a function that did that with the mutating keyword. That is actually what you have to do for methods that mutate properties in these value types, so that part of the protocol was just basically extending this part to be visible in the protocol itself.
In the example below, we have made a Person class, with the properties of firstName and lastName. In it we have a function that will change these values to a new name. We must preface this function with the mutating keyword for value types, like so:
struct Person { var firstName = "" var lastName = "" mutating func changeFirstName(first: String, last: String) { firstName = first lastName = last } }
If we neglect to put the mutating keyword in, we get the error ” Cannot assign to property: ‘ self ‘ is immutable”. You do not need to do this for reference types (namely, Classes) though, this is only something you have to do for Structures and Enumerations.
Writing And Calling Type Methods
Sometimes there may be a function that is not specific to one instance of a class. In this case, we can use a type method, which means exactly what it sounds like. It is a method associated with the type, and not a specific instance.
One great example of the use of type methods would be like the C Math library, or more to the point, reimplementing something like that. We probably would make a class and not a struct, but below I will show both to show the difference in syntax for type methods in value and reference types:
class Math { class func absoluteValue(of value: Int) -> Int { if value < 0 { return (-value) } else { return value } } } struct MathStruct { static func absoluteValue(of value: Int) -> Int { if value < 0 { return (-value) } else { return value } } }
You generally declare a method as a Type Method by using the static keyword for both Reference types and Value Type (now). If you want a subclass of a class to be able to override the Type method, you can use the class keyword instead. Prior to Swift 1.2, static was only used for value types, and class was only used for reference types, but that is no longer the case.
To call them, you don’t query a specific instance of an entity, type itself. You don’t even need to declare an instance to use type methods, as shown below:
let referenceTypeAnswer = Math.absoluteValue(of: -5) let valueTypeAnswer = MathStruct.absoluteValue(of: -5)
They are called the exact same way for the value and reference type versions. As far as calling a type method goes, it doesn’t matter whether it was written with the class or static keyword.
For another example of using type methods, check out this type method for a Point class:
struct Point { var x = 0.0 var y = 0.0 static func closestToOrigin(_ p1: Point, _ p2: Point) -> Point { let p1Distance = p1.distanceFromOrigin() let p2Distance = p2.distanceFromOrigin() if p1Distance < p2Distance { return p1 } else { return p2 } } func distanceFromOrigin() -> Double { return sqrt((x*x)+(y*y)) } } let firstPoint = Point(x: 1.5, y: 3.9) let secondPoint = Point(x: 49.2, y: 15.9) let answer = Point.closestToOrigin(firstPoint, secondPoint) answer.x //Returns 1.5 answer.y //Returns 3.9
The type method closestToOrigin does take instances of the structure, but it itself is a method that can be called from the type’s context. It even calls an instance method (distanceFromOrigin) of the Points that are passed in, to let them calculate their own distance from the origin.
Conclusion
Methods are a huge part of writing programs in just about any language. It may seem so fundamental that covering it separate from functions may seem silly. I felt there were enough nuances to warrant it getting its own post.
Type methods do come in handy occasionally. I haven’t used their equivalents very often in other programming languages, but every once in a while a type method or property can be quite useful.
I hope you found this article helpful. If you did, please don’t hesitate to share this post on Twitter or your social media of choice, every share helps. Of course, if you have any questions, don’t hesitate to contact me on the Contact Page, or on Twitter @CodingExplorer, and I’ll see what I can do. Thanks!