Stanford CS193p: Developing Applications For iOS Spring 2016
Stanford CS193p: Developing Applications For iOS Spring 2016
CS193p
Spring 2016
Today
More Swift & the Foundation Framework
What are Optionals really?
Access Control
Tuples
Range<T>
Data Structures in Swift
Methods
Properties
Array<T>, Dictionary<K,V>, String, et. al.
Initialization
AnyObject, introspection and casting (is and as)
Property List
NSUserDefaults
AnyObject in CalculatorBrain
assert
CS193p
Spring 2016
Optional
An Optional is just an enum
In other words …
enum Optional<T> { // the <T> is a generic like as in Array<T>
case None
case Some(T)
}
let x: String? = nil
… is …
let x = Optional<String>.None
Spring 2016
Optional
An Optional is just an enum
let x: String? = ...
if let y = x {
// do something with y
}
… is …
switch x {
case .Some(let y):
// do something with y
case .None:
break
}
CS193p
Spring 2016
Optional
Optionals can be “chained”
For example, hashValue is a var in String which is an Int
What if we wanted to get the hashValue from something which was an Optional String?
And what if that Optional String was, itself, contained in an Optional UILabel display?
var display: UILabel? // imagine this is an @IBOutlet without the implicit unwrap !
if let label = display {
if let text = label.text {
let x = text.hashValue
...
}
}
… or …
if let x = display?.text?.hashValue { ... }
CS193p
Spring 2016
Optional
There is also an Optional “defaulting” operator ??
What if we want to put a String into a UILabel, but if it’s nil, put “ ” (space) in the UILabel?
let s: String? = ... // might be nil
if s != nil {
display.text = s
} else {
display.text = “ “
}
… can be expressed much more simply this way …
display.text = s ?? “ “
CS193p
Spring 2016
Tuples
What is a tuple?
It is nothing more than a grouping of values.
You can use it anywhere you can use a type.
let x: (String, Int, Double) = (“hello”, 5, 0.85)
let (word, number, value) = x // tuple elements named when accessing the tuple
print(word) // prints hello
print(number) // prints 5
print(value) // prints 0.85
CS193p
Spring 2016
Tuples
Returning multiple values from a function
func getSize() -> (weight: Double, height: Double) { return (250, 80) }
let x = getSize()
print(“weight is \(x.weight)”) // weight is 250
… or …
print(“height is \(getSize().height)”) // height is 80
CS193p
Spring 2016
Data Structures in Swift
Classes, Structures and Enumerations
These are the 3 fundamental building blocks of data structures in Swift
Similarities
Declaration syntax …
class CalculatorBrain {
}
struct Vertex {
}
enum Op {
CS193p
Spring 2016
Data Structures in Swift
Classes, Structures and Enumerations
These are the 3 fundamental building blocks of data structures in Swift
Similarities
Declaration syntax …
Properties and Functions …
func doit(argument: Type) -> ReturnValue {
CS193p
Spring 2016
Data Structures in Swift
Classes, Structures and Enumerations
These are the 3 fundamental building blocks of data structures in Swift
Similarities
Declaration syntax …
Properties and Functions …
Initializers (again, not enum) …
init(argument1: Type, argument2: Type, …) {
CS193p
Spring 2016
Data Structures in Swift
Classes, Structures and Enumerations
These are the 3 fundamental building blocks of data structures in Swift
Similarities
Declaration syntax …
Properties and Functions …
Initializers (again, not enum) …
Differences
Inheritance (class only)
Value type (struct, enum) vs. Reference type (class)
CS193p
Spring 2016
Value vs. Reference
Value (struct and enum)
Copied when passed as an argument to a function
Copied when assigned to a different variable
Immutable if assigned to a variable with let
Remember that function parameters are constants
You must note any func that can mutate a struct/enum with the keyword mutating
Reference (class)
Stored in the heap and reference counted (automatically)
Constant pointers to a class (let) still can mutate by calling methods and changing properties
When passed as an argument, does not make a copy (just passing a pointer to same instance)
CS193p
Spring 2016
Methods
Parameters Names
All parameters to all functions have an internal name and an external name
func bar() {
let result = foo(externalFirst: 123, externalSecond: 5.5)
}
CS193p
Spring 2016
Methods
Parameters Names
All parameters to all functions have an internal name and an external name
The internal name is the name of the local variable you use inside the method
func bar() {
let result = foo(externalFirst: 123, externalSecond: 5.5)
}
CS193p
Spring 2016
Methods
Parameters Names
All parameters to all functions have an internal name and an external name
The internal name is the name of the local variable you use inside the method
The external name is what callers use when they call the method
func bar() {
let result = foo(externalFirst: 123, externalSecond: 5.5)
}
CS193p
Spring 2016
Methods
Parameters Names
All parameters to all functions have an internal name and an external name
The internal name is the name of the local variable you use inside the method
The external name is what callers use when they call the method
You can put _ if you don’t want callers to use an external name at all for a given parameter
func bar() {
let result = foo(123, externalSecond: 5.5)
}
CS193p
Spring 2016
Methods
Parameters Names
All parameters to all functions have an internal name and an external name
The internal name is the name of the local variable you use inside the method
The external name is what callers use when they call the method
You can put _ if you don’t want callers to use an external name at all for a given parameter
This is the default for the first parameter (except in initializers!)
func bar() {
let result = foo(123, externalSecond: 5.5)
}
CS193p
Spring 2016
Methods
Parameters Names
All parameters to all functions have an internal name and an external name
The internal name is the name of the local variable you use inside the method
The external name is what callers use when they call the method
You can put _ if you don’t want callers to use an external name at all for a given parameter
This is the default for the first parameter (except in initializers!)
For other (not the first) parameters, the internal name is, by default, the external name
func bar() {
let result = foo(123, second: 5.5)
}
CS193p
Spring 2016
Methods
Parameters Names
All parameters to all functions have an internal name and an external name
The internal name is the name of the local variable you use inside the method
The external name is what callers use when they call the method
You can put _ if you don’t want callers to use an external name at all for a given parameter
This is the default for the first parameter (except in initializers!)
For other (not the first) parameters, the internal name is, by default, the external name
Any parameter’s external name can be changed (even forcing the first parameter to have one)
func bar() {
let result = foo(forcedFirst: 123, 5.5)
}
CS193p
Spring 2016
Methods
Parameters Names
All parameters to all functions have an internal name and an external name
The internal name is the name of the local variable you use inside the method
The external name is what callers use when they call the method
You can put _ if you don’t want callers to use an external name at all for a given parameter
This is the default for the first parameter (except in initializers!)
For other (not the first) parameters, the internal name is, by default, the external name
Any parameter’s external name can be changed (even forcing the first parameter to have one)
It is generally “anti-Swift” to force a first parameter name or suppress other parameters names
func foo(first: Int, second: Double) {
var sum = 0.0
for _ in 0..<first { sum += second }
}
func bar() {
let result = foo(123, second: 5.5)
}
CS193p
Spring 2016
Methods
Obviously you can override methods/properties in your superclass
Precede your func or var with the keyword override
A method can be marked final which will prevent subclasses from being able to override
Classes can also be marked final
CS193p
Spring 2016
Properties
Property Observers
You can observe changes to any property with willSet and didSet
Will also be invoked if you mutate a struct (e.g. add something to a dictionary)
One very common thing to do in an observer in a Controller is to update the user-interface
Spring 2016
Properties
Lazy Initialization
A lazy property does not get initialized until someone accesses it
You can allocate an object, execute a closure, or call a method if you want
lazy var brain = CalculatorBrain() // nice if CalculatorBrain used lots of resources
CS193p
Spring 2016
Array
Array
var a = Array<String>()
… is the same as …
var a = [String]()
// enumerating an Array
for animal in animals {
println(“\(animal)”)
}
CS193p
Spring 2016
Array
Interesting Array<T> methods
This one creates a new array with any “undesirables” filtered out
The function passed as the argument returns false if an element is undesirable
filter(includeElement: (T) -> Bool) -> [T]
let bigNumbers = [2,47,118,5,9].filter({ $0 > 20 }) // bigNumbers = [47, 118]
CS193p
Spring 2016
Dictionary
Dictionary
var pac10teamRankings = Dictionary<String, Int>()
… is the same as …
var pac10teamRankings = [String:Int]()
CS193p
Spring 2016
String
The characters in a String
The simplest way to deal with the characters in a string is via this property …
You can think of this as an [Character] (it’s not actually that, but it works like that).
A Character is a “human understandable idea of a character”.
That will make it easier to index into the characters.
CS193p
Spring 2016
String
Other String Methods
String is automatically “bridged” to the old Objective-C class NSString
So there are some methods that you can invoke on String that are not in String’s doc
You can find them in the documentation for NSString instead.
Here are some other interesting String methods …
startIndex -> String.Index
endIndex -> String.Index
hasPrefix(String) -> Bool
hasSuffix(String) -> Bool
capitalizedString -> String
lowercaseString -> String
uppercaseString -> String
componentsSeparatedByString(String) -> [String] // “1,2,3”.csbs(“,”) = [“1”,”2”,”3”]
CS193p
Spring 2016
Other Classes
NSObject
Base class for all Objective-C classes
Some advanced features will require you to subclass from NSObject (and it can’t hurt to do so)
NSNumber
Generic number-holding class
let n = NSNumber(35.5)
let intversion: Int = n.intValue // also doubleValue, boolValue, etc.
NSDate
Used to find out the date and time right now or to store past or future dates.
See also NSCalendar, NSDateFormatter, NSDateComponents
If you are displaying a date in your UI, there are localization ramifications, so check these out!
NSData
A “bag o’ bits”. Used to save/restore/transmit raw data throughout the iOS SDK.
CS193p
Spring 2016
Initialization
When is an init method needed?
init methods are not so common because properties can have their defaults set using =
Or properties might be Optionals, in which case they start out nil
You can also initialize a property by executing a closure
Or use lazy instantiation
So you only need init when a value can’t be set in any of these ways
CS193p
Spring 2016
Initialization
What can you do inside an init?
You can set any property’s value, even those with default values
Constant properties (i.e. properties declared with let) can be set
You can call other init methods in your own class using self.init(<args>)
In a class, you can of course also call super.init(<args>)
But there are some rules for calling inits from inits in a class …
CS193p
Spring 2016
Initialization
What are you required to do inside init?
By the time any init is done, all properties must have values (optionals can have the value nil)
There are two types of inits in a class: convenience and designated (i.e. not convenience)
A designated init must (and can only) call a designated init that is in its immediate superclass
You must initialize all properties introduced by your class before calling a superclass’s init
You must call a superclass’s init before you assign a value to an inherited property
A convenience init must (and can only) call an init in its own class
A convenience init must call that init before it can set any property values
The calling of other inits must be complete before you can access properties or invoke methods
Whew!
CS193p
Spring 2016
Initialization
Inheriting init
If you do not implement any designated inits, you’ll inherit all of your superclass’s designateds
If you override all of your superclass’s designated inits, you’ll inherit all its convenience inits
If you implement no inits, you’ll inherit all of your superclass’s inits
Any init inherited by these rules qualifies to satisfy any of the rules on the previous slide
Required init
A class can mark one or more of its init methods as required
Any subclass must implement said init methods (though they can be inherited per above rules)
CS193p
Spring 2016
Initialization
Failable init
If an init is declared with a ? (or !) after the word init, it returns an Optional
init?(arg1: Type1, …) {
// might return nil in here
}
These are rare.
CS193p
Spring 2016
Initialization
Creating Objects
Usually you create an object by calling it’s initializer via the type name …
let x = CalculatorBrain()
let y = ComplicatedObject(arg1: 42, arg2: “hello”, …)
let z = [String]()
CS193p
Spring 2016
AnyObject
AnyObject is a special type (actually it’s a protocol)
Used to be commonly used for compatibility with old Objective-C APIs
But not so much anymore in iOS9 since those old Objective-C APIs have been updated
A variable of type AnyObject can point to any class, but you don’t know which
A variable of type AnyObject cannot hold a struct or an enum
There is another type, Any, which can hold anything (very, very rarely used)
CS193p
Spring 2016
AnyObject
How do we use a variable of type AnyObject?
We can’t usually use it directly (since we don’t know what class it is)
Instead, we must convert it to another, known class (or protocol)
CS193p
Spring 2016
AnyObject
Example …
Remember when we wired up our Actions in our storyboard?
The default in the dialog that popped up was AnyObject. We changed it to UIButton.
But what if we hadn’t changed it to UIButton because UISliders could also send it?
(Let’s imagine the slider slides through all the numbers 0 through 9 … silly.)
How would we have implemented touchDigit?
@IBAction func touchDigit(sender: AnyObject) {
if let sendingButton = sender as? UIButton {
let digit = sendingButton.currentTitle!
…
} else if let sendingSlider = sender as? UISlider {
let digit = String(Int(sendingSlider.value))
…
}
}
CS193p
Spring 2016
Property List
Another use of AnyObject: Property List
Property List is really just the definition of a term
It means an AnyObject which is known to be a collection of objects which are ONLY one of …
String, Array, Dictionary, a number (Double, Int, etc.), NSData, NSDate
e.g. a Dictionary whose keys were String and values were Array of NSDate is one
But wait! String, Array, Dictionary, Double … these are all structs, not classes!
Yes, but they are automatically “bridged” to Objective-C counterparts which are classes.
Objective-C is almost invisible now in the Swift API to iOS, so we’ll skip talking about bridging.
But we will talk about Property List and even give an example of it.
Property Lists are used to pass generic data structures around “blindly”.
The semantics of the contents of a Property List are known only to its creator.
Everyone else just passes it around as AnyObject and doesn’t know what’s inside.
Let’s look at an iOS API that does this: NSUserDefaults …
CS193p
Spring 2016
NSUserDefaults
A storage mechanism for Property List data
NSUserDefaults is essentially a very tiny database that stores Propery List data.
It persists between launchings of your application!
Great for things like “settings” and such.
Do not use it for anything big!
CS193p
Spring 2016
NSUserDefaults
Using NSUserDefaults
Get the defaults reader/writer …
let defaults = NSUserDefaults.standardUserDefaults()
CS193p
Spring 2016
Property List
Another example of Property List
What if we wanted to export the sequence of events that was input to the CalculatorBrain.
We could consider this the CalculatorBrain’s “program”.
To give you a head start on your assignment, let’s implement this var in CalculatorBrain …
CS193p
Spring 2016
Casting
By the way, casting is not just for AnyObject
You can cast with as (or check with is) any object pointer that makes sense
For example …
let vc: UIViewController = CalculatorViewController()
The type of vc is UIViewController (because we explicitly typed it to be)
And the assignment is legal because a CalculatorViewController is a UIViewController
But we can’t say, for example, vc.displayValue
Or we could force the cast (might crash) by using as! (with no if let) rather than as?
CS193p
Spring 2016
Assertions
Debugging Aid
Intentionally crash your program if some condition is not true (and give a message)
assert(() -> Bool, “message”)
The function argument is an “autoclosure” however, so you don’t need the { }
When building for release (to the AppStore or whatever), asserts are ignored completely
CS193p
Spring 2016