Please note, this blog entry is from a previous course. You might want to check out the current one.
Lecture #4 has no demo only theory:
Optional
Optionals are like enums:
enum Optional<T> { case None case Some(T) }
where
let x: String? = nil
equals
let x = Optional<String>.None
and
let x: String? = "hello"
is
let x = Optional<String>.Some("hello")
Unwrapping the optional like
var y = x!
would mean for the enum:
switch x { case Some(let value): y = value case None: // raise an exception }
Array
var a = Array<String>()
is the same as
var a = [String]()
Trying to append an immutable array (let) will not compile.
Accessing a not existing index will produce a crash.
Dictionary
var pac10teamRankings = Dictionary<String, Int>()
is the same as
var pac10teamRankings = [String:Int]()
Accessing an item of the dictionary returns an optional, because the result could be nil for a not existing key.
To enumerate a dictionary use tuples, e.g.:
for (key, value) in pack10teamRankings { println("\(key) = \(value)") }
Range
Ranges are defined by its endpoints of “sensible” type with a pseudo-representation like:
struct Range<T> { var startIndex: T var endIndex: T }
2…4 defines a range including the endpoints (2,3,4).
2..<4 defines an open ended range not including the endpoint (2,3)
Ranges are enumeratable, e.g.:
for i in [27...104] { }
Other Classes
- NSObject … manly to interface with Objective-C classes
- NSNumber … generic number class
- NSDate … to cope with dates and time … see also NSCalendar, NSDateFormatter, NSDateComponents
- NSData … used to save, restore, or transmit raw data
Data Structures
Swift uses classes, structures and enumerations which are quite similar:
Declaration Syntax
class CalculatorBrain {} struct Vertex {} enum Op {}
Properties and Functions
func doit(argument: Type) -> ReturnValue {} var storedProperty = <initialValue> // not for enums var computedProperty: Type { get {} set {} }
Initializers (not for enums)
init(argument1: Type, argument2: Type, ...) {}
However only classes have inheritance, introspection and casting. Structs and enums are value types. Classes are reference types.
Value Types
- are copied when passed to a function,
- are copied when assigned to another variable,
- and are immutable when assigned using let.
Note that function parameters are constants by default. Using var for a parameter creates a mutable copy. Any function which can mutate a struct or enum needs to marked with the keyword mutating.
Reference Types
- are stored in the heap,
- and are mutable when passed to a function, even if constant (let) pointers are used.
Usually choose classes. Use structures for fundamental types and enumerations for data with discrete values.
Methods
To override a method or property of the parent class mark them with the keyword override. To prevent subclasses from overriding add the keyword final.
To define a type method add the keyword static or class respectively.
All parameters have an internal (used within the method) and an external name (used by the caller):
func foo(external internal: Int) { let local = internal } func bar() { let result = foo(external: 123) }
To omit the external name use an underscore “_” instead – which is the default for the first parameter (but the init method). To force the same internal and external name for the first parameter use the hash sign e.g. “#internal“. For all other parameters the internal and external names are the same by default. Omitting (“_”) the external names for any but the first parameter is “anti-Swift”.
Properties
Property Observers
You can observe the changes to any property using willSet and didSet where newValue and oldValue provide access to the the future or previous values.
Lazy Initialization
Properties marked with “lazy” only get initialized when they are accessed the first time.
Initialization
init methods are normally not used, if values can be set using defaults, they are optionals, they are initialized using closures, or by lazy initialization.
Inside an init you can
- set any property, even those with default values,
- set constant properties,
- call other init methods of the same class
- or call init methods of the parent class
You are required to
- set all properties before the init is done or an init of the parent class is called,
- from a designated init call only a designated init of the immediate parent class,
- call a parents init before assigning an inherited property,
- and from a convenience init call a designated init of the same class (or at lease call it indirectly through another convenience init) before setting any property.
If you do not implement any designated init, you inherit all of its parent designated inits.
If you override all designated inits of the parent, you inherit all convenience inits.
If you override no inits, you inherit all inits.
Inits marked as required must be implemented by any sub class.
Inits marked with a question or exclamation mark return optionals.
AnyObject
This special protocols is primarily used for compatibility with existing Objective-C-based APIs.
To cast AnyObject (or any other type) to a specific type us “as” or “as?“, or to check before casting “is“.
Array<T> Methods
+= [T] // add another array first -> T? // get first element last -> T? // get last element append(T) // add element insert(T, atIndex: Int) // insert element splice(Array<T>, atIndex: Int) // insert array removeAtIndex(Int) // remove element removeRange(Range, [T]) // remove range of elements sort(isOrderedBefore: (T,T) -> Bool) // sort array // filter out undesired elements filter(includeElement: (T) -> Bool) -> [T] // transform array into new array map(transform: (T) -> U) -> [U] // reduce array to single value reduce(initial: U, combine: (U, T) -> U) -> U
String
A string is not an array of characters!
// get index of 3rd glyph let index = advance(s.startIndex, 2) // insert charaters s.splice("abc", index) // get start position let startIndex = advance(s.StartIndex, 1) // get position of 6h glypth let endIndex = advance(s.StartIndex, 6) // get sub string let substring = s[index..<endIndex] // get whole-number part of double let num = "56.25" if let decimalRange = num.rangeOfString(".") { let wholeNumberPart = num[num.startIndex..<decimalRange.startIndex] } // remove the whole-number part s.removeRange([s.startIndex..<decimalRange.startIndex]) replaceRange(Range, String) // replace part of an string // more methods description -> String endIndex -> String.Index hasPrefix(String) -> Bool hasSuffix(String) -> Bool toInt() -> Int? capitalizedString -> String lowercaseString -> String uppercaseString -> String join (Array) -> String componentsSeparatedByString(String) -> [String]
Type Conversion
Int(T) -> Int Double(T) -> Double CGFloat(T) -> CGFloat Array(String) -> [Character] String([Character]) -> String String(Int) -> String "\(T)" -> String
Assertions
Assertions are debugging aids to intentionally crash a program on certain conditions.
assert(() -> Bool, String)
When built for release, assertions are ignored completely.
The lecture and its slides are available via iTunes named “4. More Swift and Foundation Frameworks”.