Manipulating Numbers and Strings
Every program needs to store data temporarily in variables. However, for a program to be useful, it must also manipulate that data somehow to calculate a useful result. A spreadsheet lets you add, subtract, multiply, and divide numbers. A word processor manipulates text to correct your spelling and format text. Even a video game responds to joystick movements to calculate a new position for the player’s object such as a cartoon person, airplane, or car. Using data to calculate a new result is the whole purpose of every program.
To manipulate numbers, Swift includes four basic mathematic operators for addition (+), subtraction (-), multiplication (*), division (/), and a remainder operator (%). You can even manipulate strings using the additional operator (+) when you want to combine two strings into one.
Although Swift includes multiple operators for manipulating numbers and text, the Cocoa framework includes plenty of more powerful functions for manipulating numbers and strings. If none of these functions prove suitable, you can always create your own functions to manipulate text and numeric data. By creating miniature programs called functions, you can manipulate data in any way you like and reuse your function as often as necessary.
The simplest way to manipulate numbers is to perform addition, subtraction, division, or multiplication. When manipulating numbers, first make sure all your numbers are the same data type such as all integers or all Float or Double decimal numbers. Since mixing integers with decimal numbers can lead to calculation errors, Swift will force you to use all the same data types in a calculation. If all your data isn’t the same data type, you’ll need to convert one or more data types such as:
var cats = 4
var dogs = 5.4
dogs = Double(cats) * dogs
In this case, Swift infers that “cats” is an Int data type and “dogs” is a Double data type. To multiple cats and dogs, they must be the same data type (Double), so we must first convert the “cats” value to a Double data type and then the calculation can proceed safely.
When using multiple mathematical operators, use parentheses to define which calculations should occur first. Swift normally calculates mathematical operators from left to right, but multiplication and division occur before addition and subtraction. If you typed the following Swift code, you’d get two different results based solely on the order of the mathematical calculations:
var cats, dogs : Double
dogs = 5 * 9 - 3 / 2 + 4 // 47.5
cats = 5 * (9 - 3) / (2 + 4) // 5.0
For clarity, always group mathematical operators in parentheses. The most common mathematical operators are known as binary operators because they require two numbers to calculate a result, as shown in Table 6-1.
Table 6-1. Common mathematical operators in Swift
Mathematical operator |
Purpose |
Example |
---|---|---|
+ |
Addition |
5 + 9 = 14 |
- |
Subtraction |
5 – 9 = -4 |
* |
Multiplication |
5 * 9 = 45 |
/ |
Division |
5 / 9 = 0.555 |
% |
Remainder |
5 % 9 = 5 |
Out of all these mathematical operators, the remainder operator may need some additional explanation. Essentially the remainder operator divides one number into another and returns just the remainder of that division. So 5 divided by 9 is 0 with a remainder of 5 and 26 divided by 5 would give a remainder of 1.
When using the addition or subtraction operators to add or subtract 1, Swift gives you two options. First, you can create simple mathematical statements like this:
var temp : Int = 1
temp = temp + 1
temp = temp - 1
As a shortcut, Swift also offers something called prefix and postfix increment and decrement operators. So if you wanted to add 1 to any variable, you could just do one of the following:
var temp : Int = 1
++temp
--temp
The ++ or -- operator tells Swift to add or subtract 1 to the variable. When the ++ or -- operator appears in front of a variable, that’s called prefix and that means add or subtract 1 to the variable before using it.
If the ++ or -- operator appears after a variable, that’s called postfix and that means add or subtract 1 to the variable after using it.
To see how these different increment and decrement operators work, create a new playground by following these steps:
import Cocoa
var temp, temp2 : Int
temp = 1
temp2 = temp
print (++temp)
print (temp2++)
print (temp2)
Notice that the prefix operator (++temp) adds 1 to the variable before using it while the postfix operator (temp--) uses the variable and then adds 1 to it as shown in Figure 6-1.
Figure 6-1. Seeing how prefix and postfix operators work
The increment (++) and decrement (- -) operators let you add or subtract 1 to a variable. If you want to add or subtract a number other than 1 to a variable, you can use a compound assignment operator that looks like this (+=) or (-=).
To use a compound assignment operator, you need to specify a variable, the compound assignment operator you want to use, and then the value you want to add or subtract such as:
temp += 5
This is equivalent to:
temp = temp + 5
To see how compound assignment operators work, follow these steps:
import Cocoa
var temp : Int
temp = 2
temp += 57 // Equivalent to temp = temp + 57
print (temp)
temp -= 7 // Equivalent to temp = temp - 7
print (temp)
As Figure 6-2 shows, the += compound assignment operator adds 57 to the current value of temp. Then the -= compound assignment operator subtracts 7 from the current value of temp.
Figure 6-2. Seeing how compound assignment operators work
By combining mathematical operators, you can create any type of calculation. However if you need to perform common mathematical operations such as finding the square root or logarithm of a number, it’s much simpler and more reliable to use built-in math functions that are part of the Cocoa framework.
The Cocoa framework provides dozens of math functions that you can view by choosing Help Documentation and API Reference. When the Documentation window appears, type math and choose math under the API Reference category as shown in Figure 6-3.
Figure 6-3. Viewing the list of all math functions in the Documentation window
You likely won’t need or use all available math functions. Some of the more common math functions include the following:
When you’re working with decimal numbers, you may want to round them to the nearest place value. However, there are many ways to round numbers in Swift such as:
To see how these different rounding functions work, create a new playground by following these steps:
import Cocoa
var testNumber : Double
testNumber = round(36.98)
testNumber = round(-36.98)
testNumber = round(36.08)
testNumber = floor(36.98)
testNumber = floor(-36.98)
testNumber = floor(36.08)
testNumber = ceil(36.98)
testNumber = ceil(-36.98)
testNumber = ceil(36.08)
testNumber = trunc(36.98)
testNumber = trunc(-36.98)
testNumber = trunc(36.08)
Notice how each type of rounding function works differently with both negative and positive numbers as well as how each function rounds up or down as shown in Figure 6-4.
Figure 6-4. Seeing how different rounding functions work
You can combine Swift’s four basic mathematical functions (addition, subtraction, division, and multiplication) to create sophisticated calculations of any kind. However, the Cocoa framework includes common types of mathematical functions that you can use so you don’t have to create them yourself. Some common calculation functions include:
To see how these different calculation functions work, follow these steps:
import Cocoa
var testNumber : Double
testNumber = fabs(52.64)
testNumber = fabs(-52.64)
testNumber = sqrt(5)
testNumber = cbrt(5)
testNumber = hypot(2, 3)
testNumber = fmax(34.2, 89.2)
testNumber = fmin(34.2, 89.2)
Notice how each type of calculation function works differently as shown in Figure 6-5.
Figure 6-5. Seeing how different calculation functions work
If you remember from school (or even if you don’t), trigonometry is a mathematical field involving angles between intersecting lines. Since trigonometry can actually be handy in the real world, the Cocoa framework provides plenty of functions for calculating cosines, hyperbolic sines, inverse tangents, and inverse hyperbolic cosines. Some common trigonometry functions include:
To see how these different trigonometry functions work, follow these steps:
import Cocoa
var testNumber : Double
testNumber = sin(1)
testNumber = cos(1)
testNumber = tan(1)
testNumber = sinh(1)
testNumber = cosh(1)
testNumber = tanh(1)
testNumber = asin(1)
testNumber = acos(1)
testNumber = atan(1)
testNumber = asinh(1)
testNumber = acosh(1)
testNumber = atanh(1)
Notice how each type of trigonometry function works differently as shown in Figure 6-6.
Figure 6-6. Seeing how different trigonometry functions work
Exponential functions involve multiplication such as multiplying the number 2 by itself a fixed number of times. Some common exponential functions include:
To see how these different trigonometry functions work, follow these steps:
import Cocoa
var testNumber : Double
testNumber = exp(3)
testNumber = exp2(3)
testNumber = __exp10(3)
testNumber = expm1(3)
testNumber = pow(2,4)
Notice how each type of trigonometry function works differently as shown in Figure 6-7.
Figure 6-7. Seeing how different exponential functions work
Logarithm functions allow multiplication, division, and addition of large numbers in calculations similar to exponential functions. Some common logarithmic functions include:
To see how these different logarithmic functions work, follow these steps:
import Cocoa
var testNumber : Double
testNumber = log(3)
testNumber = log2(3)
testNumber = log10(3)
testNumber = log1p(3)
Notice how each type of logarithmic function works differently as shown in Figure 6-8.
Figure 6-8. Seeing how different logarithmic functions work
Just as the Cocoa framework provides dozens of math functions, so does it also contain a handful of string manipulation functions. Some common string functions include:
When using the + operator to append or combine strings, be careful of spaces. If you omit spaces, then you might get unwanted results. For example, “Hello” + “world” would create the string “Helloworld” without any spaces. That’s why you need to make sure you put a space in between words such as “Hello” + “world” to create “Hello world.”
To see how these different string functions work, follow these steps:
import Cocoa
var text : String = "Hello everyone!"
print (text.capitalizedString)
print (text.lowercaseString)
print (text.uppercaseString)
print (text.isEmpty)
print (text.hasPrefix ("Hello"))
print (text.hasSuffix ("world"))
var dog : Double
dog = "23.79".doubleValue
Notice how each type of string function works differently as shown in Figure 6-9.
Figure 6-9. Seeing how different string functions work
Creating Functions
Up until now, all of the functions you’ve been using to manipulate numbers or strings have been created for you in the Cocoa framework. The basic idea behind a function is that you can use it without knowing how it works. All you need to know is the function name (to call it and make it run) along with any data you might need to pass to the function so it can do something with it (such as capitalizing all the text in a string).
You should always strive to use the built-in functions of the Cocoa framework as much as possible because this lets you create programs by using pretested, reliable code. Of course, the Cocoa framework can’t provide every possible function that you may need so you’ll eventually need to create your own functions.
The purpose of functions is to simplify code. Rather than include multiple lines of code to calculate the square root of a number, it’s much simpler to hide that code in a function and just run or call that function by name. Functions basically replace multiple lines of code with a single line of code known as a function call.
The three types of functions you can create are:
Remember, functions that accept data can also return values.
Simple Functions Without Parameters or Return Values
The simplest function just consists of a function name such as this:
func functionName () {
}
By inserting one or more lines of code in between the curly brackets, you can make the function do something such as:
func simpleFunction () {
print ("Hello")
print ("there")
}
To run the code inside a function, you just need to call that function by name such as:
simpleFunction()
To see how this function works, follow these steps:
import Cocoa
func simpleFunction () {
print ("Hello")
print ("there")
}
var i = 1
while i <= 5 {
simpleFunction()
i = i + 1
}
This code defines a simple function that does nothing but print “Hello” and “there.” Then it uses a loop (which you’ll learn about later) that runs five times and runs or calls the simpleFunction five times as shown in Figure 6-10.
Figure 6-10. Defining and calling a simple function
Without a function, the same Swift code might look like this:
import Cocoa
var i = 1
while i <= 5 {
print ("Hello")
print ("there")
i = i + 1
}
While this looks simpler, the problem is if you need to reuse this code in multiple parts of a program. That means you’d need to copy and paste the same code in multiple locations. Now if you need to change the code, you’ll need to make sure you change that code throughout your program. Miss one copy of your code, and your program may no longer work right.
By storing commonly used code in a function, you store it in one place but can use it in multiple parts of your program. Now if you need to change the code, you just change it in one place and those changes automatically affect multiple parts of your program where you call that function.
Simple Functions With Parameters
Simple functions without parameters can only do the same thing over and over again. Parameters let functions accept data and use that data to calculate a different result. To define a parameter, you just need to define a descriptive name and its data type, much like declaring a variable but without using the “var” keyword such as:
func functionName (parameter: dataType) {
}
To call a function that defines a parameter, you just need to type the function name followed by the correct number of parameters such as:
functionName (parameter)
When calling functions with parameters, you need to make sure you pass the correct number of parameters and each parameter is of the correct data type. So if you had a function that accepted a one string parameter like this:
func parameterFunction (name : String) {
}
You could call this parameter by its name and with one (and only one) string inside parentheses like this:
parameterFunction("Oscar")
There are three ways a function call can fail:
In this example, the parameterFunction expects one parameter that must be a String data type. If you give parameterFunction zero or two parameters, it won’t work. Likewise, if you give parameterFunction one parameter but it’s not a String data type, it also won’t work.
To see how a function with parameters works, follow these steps:
import Cocoa
func parameterFunction (name : String) {
print ("Hello, " + name)
}
parameterFunction("Oscar")
This Swift program calls parameterFunction and passes it one string parameter (“Oscar”). When the parameterFunction receives this parameter (“Oscar”), it stores it in its name variable. Then it prints “Hello, Oscar” as shown in Figure 6-11.
Figure 6-11. Passing a string parameter to a function
Although this example uses one parameter, there’s no limit to the number of parameters a function can accept. To accept more parameters, you would just need to define additional variable names and data types like this:
func functionName (parameter: dataType, parameter2 : dataType) {
}
Each parameter can accept different data types so you can pass a function a string and an integer such as:
func functionName (parameter: String, parameter2 : Int) {
}
To call this function, you would specify the function name and its two parameters of the proper data type:
functionName ("Hello", 48)
If you pass the parameters in the wrong order, the function call won’t work such as:
functionName (48, "Hello")
When passing parameters, always make sure you pass the correct number of parameters and the proper data types in the right order as well.
Functions With Parameters That Return Values
The most versatile functions are those that use parameters to accept data and then return a value based on that data. The basic structure of a function that returns a value looks like this:
func functionName (parameter: ParameterDataType) -> DataType {
return someValue
}
The function name is any arbitrary name you want to use. Ideally, make the function name descriptive of its purpose.
The parameter is much like declaring a variable by specifying the parameter name and its data type that it can accept. Parameters are optional but functions without parameters aren’t generally useful since they perform the same tasks over and over.
The -> symbol defines the data type that the function name represents.
The return keyword must be followed by a value or commands that calculate a value. This value must be of the same data type that follows the -> symbols.
Suppose you had a function defined as follows:
func salesTax (amount: Double) -> Double {
let currentTax = 0.075 // 7.5% sales tax
return amount * currentTax
}
This function name is salesTax, it accepts one parameter called amount, which can store a Double data type. When it calculates a result, that result is also a Double data type as identified by Double after the -> symbol. The return keyword identifies how the function calculates a value to return.
To see how this function works, follow these steps:
import Cocoa
func salesTax (amount: Double) -> Double {
let currentTax = 0.075
return amount * currentTax
}
let purchasePrice = 59.95
var total : Double
total = purchasePrice + salesTax(purchasePrice)
print ("Including sales tax, your total is = (total)")
Notice that this code calls the salesTax function by passing it the value stored in purchasePrice. When you type this code in playground, you’ll see the results displayed in the right margin as shown in Figure 6-12. Try changing the values stored in purchasePrice and currentTax to see how it affects the results that this Swift code calculates.
Figure 6-12. Defining and calling a function
When a function returns a value, make sure you specify:
When calling a function that returns a value, make sure the data types match. In the above example, the salesTax function returns a Double data type so in the Swift code, this salesTax function value gets stored in the “total” variable, which is also a Double data type.
Defining External Parameter Names
When a function uses one or more parameters to accept data, you just need to define the parameter name followed by its data type such as:
func storeContact (name: String, age : Int) {
}
To call this function, you just have to use the function name and give it a string and integer such as:
storeContact ("Fred", 58)
The problem when passing parameters is that you can only see the data you’re passing but may not fully understand what it represents. To solve this problem, Swift lets you create external parameter names that force you to identify the data you’re passing to a function.
One way to do this is to create an external parameter name such as:
func functionName (externalName internalName: dataType) {
}
When you define both an external and internal name for a parameter, you use the external parameter name when passing parameters to a function, but you use the internal parameter name within the function itself. To see how to use external and internal parameter names, follow these steps:
import Cocoa
func greeting (person name : String) -> String {
return "Hello " + name
}
var message : String
message = greeting (person: "Bob")
print (message)
This function has an external parameter name of “person” and an internal parameter name of “name.” To call this function, you must include the external parameter name “person”:
greeting (person: "Bob")
External parameter names simply make calling a function and passing parameters more understandable.
When a function accepts parameters, it treats that parameter like a constant. That means within the function, Swift code cannot modify that parameter. If you want to modify a parameter within a function, then you need to create a variable parameter by identifying the parameter with the “var” keyword as follows:
func functionName (var parameter: dataType {
}
To see how variable parameters work, follow these steps:
import Cocoa
func internalChange (var name : String) {
name = name.uppercaseString
print ("Hello " + name)
}
internalChange ("Tasha")
Within the internalChange function, the name parameter changes. The first line in the internalChange function changes the name parameter into uppercase. However, any changes the internalChange function makes to the name parameter has no effect in any other part of your program. All changes stay isolated within the internalChange function.
If you want to change a parameter and have those changes take effect outside a function, then you need to use inout parameters instead.
There are two ways to pass data to a function. One is to pass a fixed value such as:
sqrt(5)
A second way is to pass a variable that represents a value such as:
var z : Double = 45.0
var answer : Double
answer = sqrt(z)
In this Swift code, the value of z is 45.0 and is passed to the sqrt function. No matter what the sqrt function does, the value of z still remains 45.0.
If you want a function to change the value of its parameters, you can create what’s called in-out parameters. That means when you pass a variable to a function, that function changes that variable.
To define a parameter that a function can change, you just have to identify that parameter using the inout keyword such as:
func functionName (inout parameter: dataType) {
}
If a function has two or more parameters, you can designate one or more parameters as inout parameters. When you identify a parameter as an inout parameter, then the function must change that inout parameter. When you call a function and pass it an inout parameter, you must use the & symbol to identify an inout parameter such as:
functionName (&variable)
To see how inout parameters work, follow these steps:
import Cocoa
func changeMe (inout name: String, age: Int) {
print (name + " is (age) years old")
name = name.uppercaseString
}
var animal : String = "Oscar the cat"
changeMe (&animal, age: 2)
print (animal)
The changeMe function defines two parameters:
The changeMe function must modify the inout parameter somehow, which it does by changing the name parameter to uppercase as shown in Figure 6-13.
Figure 6-13. Using inout parameters
Calling the changeMe function sends it a String variable called “animal,” which holds the string “Oscar the cat.” The changeMe function expects two parameters where the first one is an inout parameter. That means calling the changeMe function must meet the following criteria:
Before calling the changeMe function, the “animal” variable contains the string “Oscar the cat.” After calling the changeMe function, the “animal” variable now contains the string “OSCAR THE CAT.” That’s because the inout parameter in the changeMe function modified it.
Understanding IBAction Methods
If you remember in Chapter 5, you linked a button from the user interface to your Swift code to create an IBAction method, which is nothing more than a function that looks like this:
@IBAction func changeCase(sender: NSButton) {
labelText.stringValue = messageText.stringValue.uppercaseString
let warning = labelText.stringValue
}
Now that you understand how functions work, let’s dissect this line by line. First, @IBAction identifies a function that only runs when the user does something to a user interface item. If you look at the parameter list, you’ll see (sender: NSButton), which tells you that when the user clicks on a button, the changeCase function will run the Swift code enclosed within the curly brackets.
The Swift code stored in any IBAction method typically manipulates data somehow. In this case, it converts text from a text field (represented by the IBOutlet variable messageText), converts it to uppercase, and then displays that uppercase text in a label (represented by the IBOutlet variable labelText).
Since it’s possible for two or more user interface items to connect to the same IBAction method, the sender parameter identifies which button the user clicked on. Since this IBAction method only connects to one button, the sender parameter is ignored.
IBAction methods are nothing more than special functions linked to items on your user interface. Within any program, you’ll likely have multiple IBAction methods (functions) along with any additional functions you may have defined.
In addition, you’ll likely use functions defined in the Cocoa framework even if you never see the actual code that makes those functions work. When creating any program, you’ll use functions in one form or another.
Summary
The heart of any program is its ability to accept data, manipulate that data, and then return a useful result. The simplest way to manipulate numeric data is through common mathematical operators such as + (addition), - (subtraction), / (division), * (multiplication), and % (remainder). The common way to manipulate strings is through concatenation using the + operator, which combines two strings together.
As a shortcut, you can use the increment and decrement operators to add or subtract 1 from a variable. If you need to add or subtract values other than 1, you can use compound assignment operators instead.
Beyond these basic operators, you can also manipulate data through functions defined by the Cocoa framework. You don’t have to know how these functions work; you just have to know they exist so you can use them in your own program by calling these function names. To find function names you can use, you may need to search through Xcode’s documentation window.
While there are plenty of functions you can use from the Cocoa framework, you may need to create your own functions as well. Functions typically accept one or more parameters so they can calculate different results.
A function can represent a single value, which means you need to define the data type that the function represents.
At the simplest level, you need to define parameters with a unique name and a data type. To make parameters more understandable, you can create external parameter names, which means you need to identify the parameter name when you pass data to a function.
Normally when a function accepts a parameter, it treats that parameter like a constant that doesn’t change in value. However, functions can modify parameters by creating variable parameters using the “var” keyword. Any changes a function makes to a variable parameter stays isolated within that function.
For greater flexibility, functions can also create inout parameters that can modify the value of a parameter. When a function modifies an inout parameter, those changes appear outside of that function.
By defining your own functions, you can make and create libraries of useful code that you can reuse in other parts of your program or even in other projects as well. Functions let you create specific ways to manipulate data for your particular program.