☀ The one-day version of this course mentions only
Apple’s online documentation for Swift 4.2:
print
)
and
API Reference
A
variable
is a container inside the computer,
usually containing one number.
There are many types of variables and the simplest type is named
Int
.
A variable of this type can contain only a number that is an
integer
(whole number).
It cannot contain a number that has a fraction.
var i: Int = 10; //Create a variable named i. (This is a comment.) let j: Int = 20; //Create a constant named j.
Since the numbers
10
and
20
have no decimal point and fraction,
the computer can figure out that they’re integers.
We can therefore omit the
type
annotations:
var i = 10; //Create a variable named i. let j = 20; //Create a constant named j.
But I would feel safer if you wrote the type annotation. The semicolon is also optional.
We can change the value (contents) of a variable, but not the value of a constant. That’s why they’re called “variable” and “constant”.
var i: Int = 10; //Create the variable and put 10 into it. i = 20; //Change the value of the variable to 20. i = 30 + 40; //Change the value of the variable to 70. i = 2 * i; //Change the value of the variable to 140. i = i + 1; //Change the value of the variable to 141. i += 1; //Change the value of the variable to 142. (Swift 5 does not have the ++ or -- operators).
The name of a variable can be more than one letter. The number 9,223,372,036,854,775,807 is pronounced “9 quintillion, 223 quadrillion, 372 trillion, 36 billion” etc.
var i: Int = 10; //occupies 64 bits on iPhone 8 and iPhone XR, 32 bits on my 5th generation iPod touch let maximum: Int = 9223372036854775807; //maximum on iPhone 6s: 263 - 1 let minimum: Int = -9223372036854775808; //minimum on iPhone 6s: -263 let maximum: Int = 9_223_372_036_854_775_807; //easier way to write the same thing let maximum: Int = Int.max; //easiest way to write the same thing let minimum: Int = Int.min;
var f: Float = 3.14159; //single precision can hold up to 6 significant digits var d: Double = 3.14159265358979; //double precision can hold up to 15 significant digits var length: CGFloat = 10.25; //for lengths and coördinates on the screen; CG stands for Core Graphics. var latitude: CLLocationDegrees = 40.75; //CL stands for Core Location
var b: Bool = true; //or false. Named after George Boole. var c: Character = "A"; //exactly one character, no more and no less var s: String = "Hello, world!"; //any number of characters, including zero of them
A program can be divided into sections called
functions.
Each function has a name.
For example, there’s a function named
print
.
This function will print some text;
that’s why it’s named
“print
”.
An item of information that we feed into a function is called a
parameter
of the function.
For
print
,
the parameter is a
String
containing the line of text that we want to print.
Write the parameter in
(
parentheses)
after the function’s name.
let i: Int = 10; let j: Int = 20; var s: String = "The value of i is i."; //Put "The value of i is i." into s. s = "The value of i is \(i)."; //Put "The value of i is 10." into s. s = "The value of i+j is \(i+j)."; //Put "The value of i+j is 30." into s. print("New York"); //Print "New York" to standard output. print(s); //Print "The value of i+j is 30.". print("The value of i+j is \(i+j)."); //Print "The value of i+j is 30.".
Another way to see the value of a Swift variable is by creating a playground file. (See also Playgrounds on iPad.)
Launch Xcode.
(I have Xcode version 14.2 (14C18).)
File →
New →
Playground…
Choose a template for your new playground:
iOS
Blank
Next
Name: MyPlayground
Platform: iOS
Next
Save the new file
MyPlayground.playground
on your Desktop.
Create
import UIKit var str = "Hello, playground" var i: Int = 10; print("The value of i is \(i)."); i = 10 + 20; i = i + 10; i += 10; 10 + 20; 1 / 3; 1.0 / 3.0; 1.0 / 0.0; Int.max; Double.pi;
To see the output of your
print
s
in a separate panel that you can copy and paste,
View →
Debug Area →
Show Debug Area
To save the
.playground
file and get out of Xcode,
File → Save
Xcode → Quit Xcode
A big variable that contains little variables is called a structure. The little variables stored inside the structure are called the stored properties (or fields) of the structure. Think of them as the structure’s internal organs.
CGPoint
and
CGSize
are two types of structure that each have two stored properties of type
CGFloat
.
But the structures are used for totally different purposes.
The properties of a
CGPoint
might be negative, but the properties of a
CGSize
should never be negative.
(CG
stands for Core Graphics.)
The
CGPoint
function
is a
memberwise
initializer
that takes two
parameters.
The
0.0
and
0.0
are arguments.
The
x:
and
y:
are
argument
labels.
They remind you of the purpose of the arguments.
var p: CGPoint = CGPoint(x: 0.0, y: 0.0); //create a structure p holding the values 0.0 and 0.0 var s: CGSize = CGSize(width: 375.0, height: 667.0); //create a structure s holding the values 375.0 and 667.0
The stored properties inside a
CGPoint
are named
x
and
y
.
In this case,
the stored property names are the same as the argument labels of the function
that created the structure variable.
Write the name of the structure variable to the left of the
dot,
and the name of the property to the right.
var p: CGPoint = CGPoint(x: 0.0, y: 0.0); var x: CGFloat = p.x; var y: CGFloat = p.y;
The stored properties inside a
CGSize
are named
width
and
height
.
var s: CGSize = CGSize(width: 375.0, height: 667.0); var w: CGFloat = s.width; var h: CGFloat = s.height;
//Find the midpoint between point a and point b. let a: CGPoint = CGPoint(x: 10.0, y: 20.0); let b: CGPoint = CGPoint(x: 30.0, y: 40.0); let midpoint: CGPoint = CGPoint(x: (a.x + b.x) / 2.0, y: (a.y + b.y) / 2.0); print("The midpoint is \(midpoint).");
The output is
The midpoint is (20.0, 30.0).
In the
location manager app,
the properties inside a
CLLocationCoordinate2D
structure will be named
latitude
and
longitude
.
(CL
stands for Core Location.)
A structure is not limited to containing two properties.
A tailor might need a structure containing bust, waist, hips.
A weather report might need a structure containing
temperature, humidity, barometric pressure, and wind speed.
A structure can contain smaller structures as its properties.
For example,
a
CGRect
contains a
CGPoint
named
origin
and a
CGSize
named
size
.
var r: CGRect = CGRect(x: 0.0, y: 0.0, width: 375.0, height: 667.0); var p: CGPoint = r.origin; //The properties inside of r var s: CGSize = r.size; //are named r.origin and r.size //An expression can have more than one dot, //like the expression 10+20+30 has more than one plus. var x: CGFloat = p.x; var y: CGFloat = r.origin.y;
Here’s a diagram of the above structure
r
and its contents.
By default, the iPhone will execute every statement of the program exactly once, starting at the top and working its way down to the bottom. To do anything other than this straight-line execution, we have to use control structure statements.
We don’t have to write
(
parentheses)
around the expression
x < 0
,
but we do have to write the
{
curly braces}
around the block of statements that is to be executed or skipped.
let x: Int = 10; var message: String; var sign: Int; if x < 0 { message = "x is negative"; sign = -1; }
//Steer the computer in one of two possible directions. //In other words, execute one of two possible blocks of statements. if x < 0 { message = "x is negative"; sign = -1; } else { message = "x is non-negative"; sign = 0; }
//Steer the computer in one of three possible directions. if x < 0 { message = "x is negative"; sign = -1; } else if x == 0 { //== tests for equality, no space between them message = "x is zero"; sign = 0; } else { message = "x is positive"; sign = 1; }
The value of the expression
2018 / 400
is 5 (the
quotient,
truncated to an integer).
The value of the expression
2018 % 400
is 18 (the
remainder).
//Steer the computer in one of four possible directions. let year: Int = 2018; var isLeap: Bool; if year % 400 == 0 { isLeap = true; //year is a multiple of 400 } else if year % 100 == 0 { isLeap = false; //year is a multiple of 100, but not of 400 } else if year % 4 == 0 { isLeap = true; //year is a multiple of 4, but not of 100 or 400 } else { isLeap = false; //year is not a multiple of 4, 100, or 400 } if isLeap { print("\(year) is a leap year."); } else { print("\(year) is not a leap year."); }
The output is
2018 is not a leap year.
The Metro North evacuation instructions steer the computer in one of four possible directions:
if it is possible to remain inside the train { remain inside the train; } else if you are able to go to next car through end doors { go to next car through end doors; } else if you are able to open the side door and get out { open the side door and get out; } else { go out emergency windows; }
//Steer the computer in one of four possible directions. var n: Int = 23; //must be non-negative var lastDigit: Int = n % 10; var suffix: String; //ordinal suffix if lastDigit == 1 { suffix = "st"; } else if lastDigit == 2 { suffix = "nd"; } else if lastDigit == 3 { suffix = "rd"; } else { suffix = "th"; } print("\(n)\(suffix)");
23rd
What is the smallest positive integer
for which the above code gives the wrong output?
The following
||
means “or”.
//Steer the computer in one of five possible directions. var n: Int = 211; //must be non-negative var lastDigit: Int = n % 10; var lastTwoDigits: Int = n % 100; var suffix: String; //ordinal suffix if lastTwoDigits == 11 || lastTwoDigits == 12 || lastTwoDigits == 13 { suffix = "th"; } else if lastDigit == 1 { suffix = "st"; } else if lastDigit == 2 { suffix = "nd"; } else if lastDigit == 3 { suffix = "rd"; } else { suffix = "th"; } print("\(n)\(suffix)");
211th
Do we always need to perform both comparisons?
Performance bug.
<=
means
“less than or equal to”.
let profit: Int = 100; let loss: Int = 110; if profit <= loss { print("We're not making any money."); } if profit < loss { print("In fact, we're losing money."); }
We're not making any money. In fact, we're losing money.
let profit: Int = 100; let loss: Int = 110; if profit <= loss { print("We're not making any money."); if profit < loss { print("In fact, we're losing money."); } }
Do we always need to perform both comparisons? Performance bug.
let profit: Int = 100; let loss: Int = 110; if profit > loss { print("We're making money."); } else { print("We're not making any money."); } if profit < loss { print("In fact, we're losing money."); }
We're not making any money. In fact, we're losing money.
let profit: Int = 100; let loss: Int = 110; if profit > loss { print("We're making money."); } else { print("We're not making any money."); if profit < loss { print("In fact, we're losing money."); } }
An
if/else
statement is easiest to read when the smaller block is above the bigger one.
var x: Int = 10; //good if x == 10 { print("+---+"); print("| |"); print("+---+"); } else { print("+---+"); print("| |"); print("| |"); print("+---+"); }What to do when the smaller block is below the bigger one?
var y: Int = 10; //bad if y == 10 { print("+---+"); print("| |"); print("| |"); print("+---+"); } else { print("+---+"); print("| |"); print("+---+"); }Simply replace the comparison operator with its opposite.
==
and !=
are a pair of opposites.
<
and >=
are a pair of opposites.
>
and <=
are a pair of opposites.
var y: Int = 10; //good if y != 10 { print("+---+"); print("| |"); print("+---+"); } else { print("+---+"); print("| |"); print("| |"); print("+---+"); }
The
square
brackets
in the expression
[0, 1, 2]
create an
array
containing the numbers 0, 1, 2.
(See also the
underscore
_
).
for var i: Int in [0, 1, 2] { print("She loves you"); print("Yeah!"); print("Yeah!"); print("Yeah!"); }
She loves you Yeah! Yeah! Yeah! She loves you Yeah! Yeah! Yeah! She loves you Yeah! Yeah! Yeah!
Instead of using the
array
[0, 1, 2]
,
we can get exactly the same output with a
range.
See
The expression
0
...
3
represents the range of numbers 0, 1, 2, 3.
The expression
0
..<
3
represents the range of numbers 0, 1, 2.
for var i: Int in 0 ..< 3 { print("She loves you"); print("Yeah!"); print("Yeah!"); print("Yeah!"); }
The computer can figure out that
i
is an
Int
variable:
for i in 0 ..< 3 { print("She loves you"); print("Yeah!"); print("Yeah!"); print("Yeah!"); }
Nested loops:
for i in 0 ..< 3 { print("She loves you"); for j in 0 ..< 3 { print("Yeah!"); } }
She loves you Yeah! Yeah! Yeah! She loves you Yeah! Yeah! Yeah! She loves you Yeah! Yeah! Yeah!
A loop that prints numbers:
for i in 0 ..< 5 { print("i = \(i)"); }
i = 0 i = 1 i = 2 i = 3 i = 4
A range does not necessarily have to start with 0:
for h in 2 ... 8 { print("\(4 * h) pierogies feed \(2 * h) people or \(h) Hungarians."); }
8 pierogies feed 4 people or 2 Hungarians. 12 pierogies feed 6 people or 3 Hungarians. 16 pierogies feed 8 people or 4 Hungarians. 20 pierogies feed 10 people or 5 Hungarians. 24 pierogies feed 12 people or 6 Hungarians. 28 pierogies feed 14 people or 7 Hungarians. 32 pierogies feed 16 people or 8 Hungarians.
To count down, we must use stride instead of a range.
We can feed arguments of type
Int
into the
stride
function
because
the data type
Int
is actually a
structure
that conforms to the
protocol
Strideable
.
But
Strideable
is not mentioned in the
developer.apple.com
documentation for
Int
.
But it is mentioned in the
SwiftDoc.org
documentation for
Int
.
for b in stride(from: 100, through: 1, by: -1) { print("\(b) bottles of beer on the wall,"); print("\(b) bottles of beer--"); print("If one of those bottles should happen to fall,"); print("\(b - 1) bottles of beer on the wall."); print(); //Skip a line. }
100 bottles of beer on the wall, 100 bottles of beer-- If one of those bottles should happen to fall, 99 bottles of beer on the wall. 99 bottles of beer on the wall, 99 bottles of beer-- If one of those bottles should happen to fall, 98 bottles of beer on the wall. 98 bottles of beer on the wall, 98 bottles of beer-- If one of those bottles should happen to fall, 97 bottles of beer on the wall. etc. 1 bottles of beer on the wall, 1 bottles of beer-- If one of those bottles should happen to fall, 0 bottles of beer on the wall.
Driving north from New York City on the New York State Thruway:
for a in stride(from: 108, through: 48, by: -10) { print("+--------------+"); print("| Albany \(a) |"); print("| Montreal \(a + 220) |"); print("| Buffalo \(a + 280) |"); print("+--------------+"); print(); //print an empty line (i.e., just a newline character) }
+--------------+ | Albany 108 | | Montreal 328 | | Buffalo 388 | +--------------+ +--------------+ | Albany 98 | | Montreal 318 | | Buffalo 378 | +--------------+ +--------------+ | Albany 88 | | Montreal 308 | | Buffalo 368 | +--------------+ +--------------+ | Albany 78 | | Montreal 298 | | Buffalo 358 | +--------------+ +--------------+ | Albany 68 | | Montreal 288 | | Buffalo 348 | +--------------+ +--------------+ | Albany 58 | | Montreal 278 | | Buffalo 338 | +--------------+ +--------------+ | Albany 48 | | Montreal 268 | | Buffalo 328 | +--------------+
See
multiline
string
literals
with triple quotes.
The
format
is one big string consisting of six lines
(the last line is empty, i.e., consists of just a newline character).
The
String(format:)
function
(whose name is really
init
)
returs the same string, but with each
%3d
replaced by a three-digit number in decimal (as opposed to octal or hex).
let format: String = """ +--------------+ | Albany %3d | | Montreal %3d | | Buffalo %3d | +--------------+ """; for a in stride(from: 108, through: 48, by: -10) { print(String(format: format, a, a + 220, a + 280)); }
+--------------+ | Albany 108 | | Montreal 328 | | Buffalo 388 | +--------------+ +--------------+ | Albany 98 | | Montreal 318 | | Buffalo 378 | +--------------+ etc. +--------------+ | Albany 48 | | Montreal 268 | | Buffalo 328 | +--------------+
The only thing the following variable
i
can contain is an integer.
var i: Int = 10; //born containing the number 10 i = 20; //change it to 20 i = 10; //change it back to 10 print("The value of i is \(i).");
The following variable can contain either an integer or the special value
nil
,
which is not an integer.
nil
stands for
“no value”.
var i: Int? = 10; //born containing the number 10. i = 20; //change it to 20 i = nil; //change it to nil i = 10; //change it back to 10 if i == nil { print("i is nil."); } else { print("i! is \(i!)."); //The exclamation point "unwraps" (i.e., gets) the non-null value. print("i is \(i)."); //Try to print it without the exclamation point. }
i! is 10. i is Optional(10).
The exclamation point can be applied
only to an optional value that is not equal to
nil
.
var i: Int? = nil; //born containing nil print("i is \(i!)."); //causes fatal error
Fatal error: Unexpectedly found nil while unwrapping an Optional value
Use
optional
binding
to unwrap the value that’s in
i
once and for all,
without using an exclamation point.
var i: Int? = 10; if var j: Int = i { //Arrive here if i was not nil. //j now contains the Int that was in i. //Since j is not an optional variable, //we can use j without writing an exclamation point. print("j contains \(j)."); j += 1; print("And now j contains \(j)."); } else { //Arrive here if i was nil. //In this case, the variable j was never created. print("i was nil."); } //j cannot be mentioned below this point. print("We are now done examining i, and can continue on to something else.");
j contains 10. And now j contains 11.
Whether or not the above
i
is
nil
,
the code eventually finishes examining
i
and continues on to something else.
If you want to halt the program if
i
is
nil
,
use
guard/else
.
var i: Int? = 10; guard let j: Int = i else { //Arrive here if i was nil. //In this case, the variable j was never created. print("i was nil. Something is probably wrong."); return; //assuming all this code was inside a function; or throw; } //Arrive here only if i was not nil. print("j = \(j)");
An implicitly unwrapped optional does not need an exclamation point to unwrap it.
//i and j are both optionals. var i: Int? = 10; //must write an ! in order to unwrap i var j: Int! = 20; //j can be unwraped without writing ! var k: Int; k = i!; //Put 10 into k. Would cause fatal error if i == nil k = j; //Put 20 into k. Would cause fatal error if j == nil
Three of the Objective-C collection classes have been built into the language Swift: sets, arrays, and dictionaries.
Use the
count
property of an array to find out how many elements are in the array.
An array is actually a
structure
whose
count
property is inherited from the
count
property of
protocol
Collection
.
The value of the expression
2018 / 12
is 168 (the
quotient,
truncated, if necessary, to an integer).
The value of the expression
2018 % 12
is 2 (the
remainder,
in the range 0 to 11 inclusive).
let animals: [String] = [ //an array containing 12 Strings "monkey", // 0 "rooster", // 1 "dog", // 2 "pig", // 3 "rat", // 4 "ox", // 5 "tiger", // 6 "hare", // 7 "dragon", // 8 "snake", // 9 "horse", //10 "sheep" //11 ]; print("The number of animals is \(animals.count)."); print("The first animal is \(animals[0])."); print("The second animal is \(animals[1])."); print("The last animal is \(animals[animals.count - 1])."); //or use the optional .last property let year: Int = 2018; print("\(year) is the year of the \(animals[year % animals.count]).");
The number of animals is 12. The first animal is monkey. The second animal is rooster. The last animal is sheep. 2018 is the year of the dog.
print("The last animal is \(animals[animals.count]).");
Fatal error: Index out of range
let animals: [String] = [ //an array containing 12 Strings "monkey", // 0 "rooster", // 1 "dog", // 2 "pig", // 3 "rat", // 4 "ox", // 5 "tiger", // 6 "hare", // 7 "dragon", // 8 "snake", // 9 "horse", //10 "sheep" //11 ]; print("count is \(animals.count)"); print("first is \(animals.first!)"); print("last is \(animals.last!)");
count is 12 first is monkey last is sheep
let liberalRepublicans: [String] = [String](); //Call the init method that creates an empty array. print("count = \(liberalRepublicans.count)"); if var f: String = liberalRepublicans.first { print("f = \(f)"); //We skip this print because the array is empty. }
count = 0
//The variable animal contains a different String each time around the loop. for var animal: String in animals { print(animal); }
monkey rooster dog pig rat ox tiger hare dragon snake horse sheep
The computer can figure out that
animal
is a
String
variable:
for animal in animals { print(animal); }
Let’s print the subscript as well as the value of each element.
The expression
(index, value)
is a
tuple,
a datatype whose name comes from double, triple, quadruple, quintuple, etc.
A tuple is a sort of informal
structure
that holds two or more values.
We can call the
enumerated
method of the array because struct
Array
conforms to protocol
Collection
,
which inherits from protocol
Sequence
,
which has the instance method
enumerated
.
for (index, value) in animals.enumerated() { print("\(index) \(value)"); }
0 monkey 1 rooster 2 dog 3 pig 4 rat 5 ox 6 tiger 7 hare 8 dragon 9 snake 10 horse 11 sheep
The value of the expression
2018 % 10
is 8.
The value of the expression
2018 / 10
is 201.
The value of the expression
201 % 10
is 1.
The value of the expression
201 / 10
is 20.
Etc.
//Four arrays of Strings. let ones: [String] = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]; let tens: [String] = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"]; let hundreds: [String] = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"]; let thousands: [String] = ["", "M", "MM", "MMM"]; var n: Int = 2018; if n > 0 && n < 4000 { let o: Int = n % 10; //let o be the rightmost digit of n n /= 10; //or n = n / 10; chop the rightmost digit off of n let t: Int = n % 10; //let t be the rightmost surviving digit of n n /= 10; let h: Int = n % 10; n /= 10; let th: Int = n % 10; print("\(thousands[th])\(hundreds[h])\(tens[t])\(ones[o])"); }
MMXVIII
//A big array containing four little arrays. //Each little array contains 10 Strings. let bigArray: [[String]] = [ ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"], ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"], ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"], ["", "M", "MM", "MMM"] ]; var n: Int = 2018; var roman: String = ""; if n > 0 && n < 4000 { for littleArray in bigArray { roman = littleArray[n % 10] + roman; n /= 10; //means n = n / 10 } print(roman); }
Incidentally, here’s how to get the current year.
let date: Date = Date(); //Call the no-parameter init method of class Date let calendar: Calendar = Calendar.current; let year: Int = calendar.component(Calendar.Component.year, from: date); print(year);
2018
let notes: [String: String] = [ //a dictionary containing two parallel columns of Strings "do": "deer, a female deer", "re": "drop of golden sun", "me": "name I call myself", "fa": "long, long way to run", "sol": "needle pulling thread", "la": "note to follow sol", "ti": "drink with jam and bread" ]; let key: String = "me"; let value: String? = notes[key]; //an optional String--it might be nil if value == nil { print("There is no note named \(key)."); } else { print("\(key): a \(value!)"); }
me: a name I call myself
The following loop is guaranteed to print all of them,
but their order is unpredictable.
The expression
(key, value)
is a
tuple.
See the dictionary in
Switch.
for (key, value) in notes { print("\(key): a \(value)"); }
me: a name I call myself do: a deer, a female deer me: a name I call myself sol: a needle pulling thread ti: a drink with jam and bread re: a drop of golden sun fa: a long, long way to run la: a note to follow sol
Create an object by calling an
init
method of the object’s class.
//Call the init method of MyClass. This method takes no parameters. let myObject: MyClass = MyClass(); let date: Date = Date(); //example from Hello app print(date);
2018-10-13 02:43:57 +0000
An
init
method might take a
parameter
such as the following
f
.
The
frame:
is an
argument
label.
It reminds us of the purpose of the parameter.
let f: CGRect = CGRect(x: 0, y: 0, width: 80, height: 40); //A UILabel is a rectangular object that holds one line of text. //Call an init method of class UILabel and pass it the parameter f. //The parameter is preceded by an argument label. //(This init method was inherited by class UILabel from class UIView.) let label: UILabel = UILabel(frame: f); //Call an init method of class UISwipeGestureRecognizer. Pass it two parameters. //Each parameter is preceded by an argument label. //(This init method was inherited by class UISwipeGestureRecognizer from class UIGestureRecognizer.) let recognizer: UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "swipe:");
Numeric type conversion uses the same syntax as initialization, but without an argument label.
let d: Double = 3.14159265358979; //could say Double.pi instead of 3.14159265358979 let i: Int = Int(d); //Put 3 into i.
Two examples from Button:
/* The constant kSystemSoundID_Vibrate is an enum, but the parameter of the function AudioServicesPlaySystemSound must be a SystemSoundID (which is another name for UInt32). */ AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate));
/* The function AudioServicesCreateSystemSoundID returns an OSStatus, which we want to compare to the enum kAudioServicesNoError. */ let status: OSStatus = AudioServicesCreateSystemSoundID(url, &sid); if status == OSStatus(kAudioServicesNoError) { AudioServicesPlaySystemSound(sid); }
Write the name of the object, a dot, the name of the method, and the parameter list in parentheses. The first parameter will usually not have an argument label, because the purpose of the first parameter will be explained by the name of the method. The remaining parameters might have argument labels.
//Where did the finger touch the screen? let point: CGPoint = touch.locationInView(self); //Does the set object contain the string "New York"? let bool: Bool = set.containsObject("New York"); s.drawAtPoint(point, withAttributes: attributes);
An
in-out parameter
is one that can be written as well as read.
The examples we will see today are in
Hello
and
Switch.
See
Error
Handling.
NS
stands for
NextSTEP.
var s: String; var error: NSError?; //Must be var, can't be let. Born containing nil. //The ampersand allows the method to give a value to the parameter. let contents: String? = String(contentsOfURL: url!, encoding: NSUTF8StringEncoding, error: &error); if contents != nil { s = contents!; } else if error != nil { s = error!.localizedDescription; } else { s = "unknown error"; }
var error: NSError? let player: AVAudioPlayer = AVAudioPlayer(contentsOfURL: url, error: &error); if error != nil { print("could not create AVAudioPlayer: \(error!)"); }
The return value of a method might have to be downcast (converted) to a more specific data type. The same is true for a value in an array. Here is an example from Set.
//The method anyObject can return an object of any type. let s: String? = mySet.anyObject() as? String; let t: String = mySet.anyObject() as! String; //as! causes fatal error if anyObject returns nil
Most methods belong to a particular object. These are called the instance methods of the object. Some methods belong to an entire class of objects, rather than to one particular object. These are called type methods. We often call a type method to get a reference to (i.e., make contact with) an existing object of the type method’s class. Here are the first examples we will see.
//We are not creating the yellow color: it already exists. //We are merely getting a reference to it. let color: UIColor = UIColor.yellowColor(); let font: UIFont = UIFont.systemFontOfSize(32); let screen: UIScreen = UIScreen.mainScreen(); let device: UIDevice = UIDevice.currentDevice(); let application: UIApplication = UIApplication.sharedApplication(); let fileManager: NSFileManager = NSFileManager.defaultManager();
We have seen several functions that are orphans. They belong to no object.
print(); //Print a newline character to the standard output. print("New York"); //Print a line, followed by a newline. var y: Double = sin(M_PI / 2); var y: Double = cos(M_PI / 2);
A
closure
is a group of Swift statements in
{
curly
braces}
passed as a parameter to a method or other function.
We will see a closure passed to the function
dispatch_after
in
Hello
and
Tap.
//t represents the time that is one second from now. //NSEC_PER_SEC is the number of nanoseconds per second (1,000,000,000). let t: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(NSEC_PER_SEC)); //Call myFunction one second from now. dispatch_after(t, dispatch_get_main_queue(), {myFunction();});
The
\t
is the
tab
character.
Lesson 7 of Intro to App Development with Swift illustrates a function with
Row, Row, Row Your Boat.
print("There's a man who leads a life of danger"); print("To everyone he meets he stays a stranger"); print("With every move he makes, another chance he takes"); print("Odds are he won't live to see tomorrow."); print(); print("\tSecret Agent Man, Secret Agent Man"); print("\tThey've given you a number, and taken 'way your name."); print(); print("Beware of pretty faces that you find"); print("A pretty face can hide an evil mind"); print("Be careful what you say, or you'll give yourself away"); print("Odds are you won't live to see tomorrow."); print(); print("\tSecret Agent Man, Secret Agent Man"); print("\tThey've given you a number, and taken 'way your name."); print(); //guitar solo print("\tSecret Agent Man, Secret Agent Man"); print("\tThey've given you a number, and taken 'way your name."); print(); print("Swinging on the Riviera one day"); print("Lying in a Bombay alley the next day"); print("Don't let the wrong words slip while kissing persuasive lips"); print("Odds are you won't live to see tomorrow."); print(); print("\tSecret Agent Man, Secret Agent Man"); print("\tThey've given you a number, and taken 'way your name."); print(); print("Secret Agent Man.");
There's a man who leads a life of danger To everyone he meets he stays a stranger With every move he makes, another chance he takes Odds are he won't live to see tomorrow. Secret Agent Man, Secret Agent Man They've given you a number, and taken 'way your name. Beware of pretty faces that you find A pretty face can hide an evil mind Be careful what you say, or you'll give yourself away Odds are you won't live to see tomorrow. Secret Agent Man, Secret Agent Man They've given you a number, and taken 'way your name. Secret Agent Man, Secret Agent Man They've given you a number, and taken 'way your name. Swinging on the Riviera one day Lying in a Bombay alley the next day Don't let the wrong words slip while kissing persuasive lips Odds are you won't live to see tomorrow. Secret Agent Man, Secret Agent Man They've given you a number, and taken 'way your name. Secret Agent Man.
func chorus() { print("\tSecret Agent Man, Secret Agent Man"); print("\tThey've given you a number, and taken 'way your name."); print(); } print("There's a man who leads a life of danger"); print("To everyone he meets he stays a stranger"); print("With every move he makes, another chance he takes"); print("Odds are he won't live to see tomorrow."); print(); chorus(); print("Beware of pretty faces that you find"); print("A pretty face can hide an evil mind"); print("Be careful what you say, or you'll give yourself away"); print("Odds are you won't live to see tomorrow."); print(); chorus(); //guitar solo chorus(); print("Swinging on the Riviera one day"); print("Lying in a Bombay alley the next day"); print("Don't let the wrong words slip while kissing persuasive lips"); print("Odds are you won't live to see tomorrow."); print(); chorus(); print("Secret Agent Man.");
We can create a new class of objects that has all of the features (properties, methods, etc.) of an existing class of objects, plus additional features. The existing class is called the superclass and the new class is called the subclass.
An object of the subclass actually contains a smaller object of the
superclass inside of it:
that’s how the subclass object
gets all the features of the superclass object.
Code that creates a subclass object must therefore remember
to execute the code that creates the superclass object.
In other words, the
init
method of a subclass must always call the
init
method of the superclass.
init() { super.init() //write code here to create the rest of the subclass object }
A
protocol
is a list of requirements that a class might have to fulfill.
For example, a class that conforms to the protocol
UIApplicationDelegate
has to have a method named
application(_:didFinishLaunchingWithOptions:)
.
(The
didFinishLaunchingWithOptions:
is an
argument
label;
we will consider it to be part of the method’s name.)
Strictly speaking,
this method is actually an
optional
method of protocol
UIApplicationDelegate
,
but you probably want to define it anyway.
A protocol in Swift is similar to an
interface
in Java.
An object can be stimulated in many ways. It can be touched by a finger, or it can reach the end of the audio file that it is playing. When the object is stimulated, we can arrange for it to automatically call a method belonging to another object, called the delegate of the original object. A delegate must belong to a class that conforms to a protocol. The first three examples we will see are
AppDelegate
conforms to the protocol
UIApplicationDelegate
.
ViewController
will conform to the protocol
AVAudioPlayerDelegate
.
ViewController
conforms to the protocol
UITextFieldDelegate
.