Intermediate Swift - Session 403
Options
String to Integer
Optional Type
var optionalNumber:Int?
// default initialized to nil
optionalNumber = 6
Non-Optional Types can't be nil
var myString:String = nil
// error
Optional Return Types
func findIndexOfString ( string : String , array : String []) -> Int ? {
for ( index , value ) in enumerate ( array ) {
if value == string {
return index
}
}
return nil
}
Optional Binding
Test and unwrap at the same time
var neighbors = [ "Alex" , "Anna" , "Madison" , "Dave" ]
let index = findIndexOfString ( "Anna" , neighbors )
//if let indexValue = index { // index is of type Int, not nil?, indexValue is of type Int
if let indexValue = findIndexOfString ( "Anna" , neighbors ) { // index is of type Int, not nil?, indexValue is of type Int
println ( "Hello, \(neighbors[indexValue])" )
}
else {
println ( "Must've moved away" )
}
Optional Chaining
if let addressNumber = paul.residence?.address?.buildingNumber?.toInt() {
addToDatabase("Paul", addressNumber)
}
Use if let
optional binding to test and unwrap at the same time
Option chaining (?) is a concise way to work with chained optionals
Memory Management
Automatic Reference Counting
Weak References are optional values
Binding the optional produces a strong reference
if let tenant = apt . tenant {
tenant . buzzIn ()
}
apt . tenant ?. buzzIn ()
Unowned References
Strong, Weak, and Unowned References
strong references are default
Initialization
Every value must
be initialized before it is used.
class RaceCar : Car {
var hasTurbo : Bool
init ( color : Color , turbo : Bool ) {
hasTurbo = turbo
super . init ( color : color )
}
// 多個 initializers
convenience init ( color : Color ) {
self . init ( color : color , turbo : true )
}
convenience init () {
self . init ( color : Color ( gray : 0 . 4 ))
}
}
class FormulaOne : RaceCar {
let minimumWeight = 642
init ( Color : Color ) {
self . init ( color : color , turbo : false )
}
}
Lazy Properties
@lazy var multiplayerManager = MultiplayerManager()
Deinitialization
class FileHandle {
let fileDescriptor : FileDescriptor
init ( path : String ) {
fileDescriptior = openFile ( path )
}
deinit {
closeFile ( fileDescriptor )
}
}
Initialize all values before you use them
set all stored properties first
, then call super.init
Designated initializers only delegate up
Convenience initializers only delegate across
Deinitializers are there... if youe need them
Closures
var clients = [ "Pestov" , "Buenaventura" , "Sreeram" , "Babbage" ]
clients . sort ({( a : String , b : String ) -> Bool in
return a < b
})
println ( clients )
用 Type Inference
簡化成
struct Array < String > {
func sort ( order : ( String , String ) -> Bool )
}
clients . sort ({ a , b in a < b })
Implicit Arguments
clients.sort({ $0 < $1 })
Trailing Closures
client.sort { $0 < $1 }
Functional Programming
println ( words . filter { $ 0 . hasSuffix ( "gry" ) })
// angry
// hungry
println ( words . filter { $ 0 . hasSuffix ( "gry" ) }
. map { $ 0 . uppercaseString })
// ANGRY
// HUNGRY
Function Values - Closures
numbers . map {
// sum += $0
println ( $ 0 )
}
// 可以簡化成
numbers . map ( println )
var indexes = NSMutableIndexSet ()
numbers . map {
indexes . addIndex ( $ 0 )
}
// 可以簡化成
numbers . map ( indexes . addIndex )
Capture Lists
class TempNotifier {
var onChange : ( Int ) -> Void = {}
var currentTemp = 72
init () {
onChange = {[ unowned self ] temp in
self . currentTemp = temp
}
}
}
Pattern Matching
Validating a Property List
func stateFromPlist ( list : Dictionary < String , AnyObject > ) -> State ?
// 正常狀況
stateFromPlist ( "name" : "California"
"population" , 38 _040_000 ,
"abbr" : "CA" )
// 當傳入錯誤的型別
// ie: population 應該要傳入數字,卻傳入字串,需要回傳 nil
stateFromPlist ( "name" : "California"
"population" , "hella peeps" ,
"abbr" : "CA" )
可以用這樣的方式檢查
func stateFromPlist ( list : Dictionary < String , AnyObject > ) -> State ? {
var name : NSString ?
switch list [ "name" ] {
case . Some ( let listName as NSString ):
name = listName
// ...
default:
name = nil
}
return name
}
有更好的方法
func stateFromPlist ( list : Dictionary < String , AnyObject > ) -> State ? {
switch ( list [ "name" ], list [ "population" ], list [ "abbr" ]) {
case (. Some ( let listName as NSString ),
. Some ( let pop as NSNumber ),
. Some ( let abbr as NSString ))
where abbr . length == 2 :
// 用 where 檢查 abbr 長度是否為2
return State ( name : listName , population : pop , abbr : abbr )
default:
return nil
}
}
總結
Optionals
Memory management
Initialization
Closures
Pattern matching