Standford 2015 iOS讀書會
week2
彼得潘
1. Applying MVC
2. More Swift and Foundation Frameworks
Applying MVC
MVC
Model: 計算機
create new class
檔名沒有強制要跟類別名⼀一樣
名稱
其它名稱: 每個單字的字⾸首⼤大寫,但第⼀一個單字的字⾸首⼩小寫
type名稱: 每個單字的字⾸首⼤大寫
儲存operand & operation
var opStack = Array<Op>()
var opStack = [Op]()
空array的表達和建⽴立
enum
enum Op {
case Operand(Double)
case UnaryOperation(String, Double->Double)
case BinaryOperation(String, (Double, Double)->Double)
}
enum也能定義init
沒有enum的混亂世界
表達清單成員的enum
enum的最佳拍檔switch
enum 成員的另⼀一⾯面
raw value
動態設定的相關聯資料
associated value
和class, struct百分之⼋八⼗十雷
同的enum
⽅方法,computed property,initializer
value type
nested type
擁有capture value魔⼒力的
nested function
nested comment
• nested comment: 

comment裡可以包comment

Objective-C不⾏行,

它需先把內部的comment消掉
像字典⼀一樣⽅方便搜尋的
dictionary
var knownOps = Dictionary<String, Op>()
var knownOps = [String:Op]()
像字典⼀一樣⽅方便搜尋的
dictionary
索引的型別須⼀一致,索引對應的資料型別也是
struct定義的dictionary
struct的移除成員
排斥重覆資料的Set
initializer
init() {
knownOps["×"] = Op.BinaryOperation("×", {$0*$1} )
}
init() {
knownOps["×"] = Op.BinaryOperation("×"){$0*$1}
}
case BinaryOperation(String, (Double, Double)->Double)
初始化物件的⽅方法
initializer
initializer
init() {
knownOps["×"] = Op.BinaryOperation("×"){$0*$1}
knownOps["÷"] = Op.BinaryOperation("÷"){$1/$0}
knownOps["+"] = Op.BinaryOperation("+"){$0+$1}
knownOps["−"] = Op.BinaryOperation("−"){$1-$0}
knownOps["√"] = Op.UnaryOperation("√"){sqrt($0)}
}
case BinaryOperation(String, (Double, Double)->Double)
initializer
init() {
knownOps["×"] = Op.BinaryOperation("×", *)
knownOps["÷"] = Op.BinaryOperation("÷"){$1/$0}
knownOps["+"] = Op.BinaryOperation("+", +)
knownOps["−"] = Op.BinaryOperation("−"){$1-$0}
knownOps["√"] = Op.UnaryOperation("√", sqrt)
}
case BinaryOperation(String, (Double, Double)->Double)
operator也是function
⾃自訂能⼒力的operator
infix, prefix, postfix
⾃自訂內建operator⾏行為
不可省略prefix或postfix,只有infix可省略
發明operator
access control
權限管理員
access control
internal,public,private
可作⽤用於class、struct、enum、property、 method、
initializer、subscript、protocol、variable、constant、function
function return optional
func evaluate() -> Double? {
}
當optional遇上function
結合資料的輕便tuple
結合資料的輕便tuple
⽤用tuple圓function
回傳多個資料的夢
當switch遇上tuple
array & dictionary, string,
double are struct
pass by value
private func evaluate(ops:[Op]) -> (result:Double?, remainingOps:[Op]) {
if !ops.isEmpty {
var remainingOps = ops
let op = remainingOps.removeLast()
switch op {
case .Operand(let operand):
return (operand, remainingOps)
case .UnaryOperation(_, let operation):
let operandEvaluation = evaluate(remainingOps)
if let operand = operandEvaluation.result {
return (operation(operand), operandEvaluation.remainingOps)
}
case .BinaryOperation(_, let operation):
let op1Evaluation = evaluate(remainingOps)
if let operand1 = op1Evaluation.result {
let op2Evaluation = evaluate(op1Evaluation.remainingOps)
if let operand2 = op2Evaluation.result {
return (operation(operand1, operand2), op2Evaluation.remainingOps)
}
}
}
}
return (nil, ops)
}
func evaluate() -> Double? {
let (result, _) = evaluate(opStack)
return result
}
recursion
function parameter is
constant by default
參數怎麼改
inout參數
option + 點選檔案
檔案顯⽰示在Assistant Editor
列印enum
private enum Op:Printable {
case Operand(Double)
case UnaryOperation(String, Double->Double)
case BinaryOperation(String, (Double, Double)->Double)
var description:String {
get {
switch self {
case .Operand(let operand):
return "(operand)"
case .UnaryOperation(let symbol, _ ):
return symbol
case .BinaryOperation(let symbol, _):
return symbol
}
}
}
}
遵從Printable protocol和定義description property
init() {
func learnOp(op:Op) {
knownOps[op.description] = op
}
learnOp(Op.BinaryOperation("×", *))
learnOp(Op.BinaryOperation("÷"){$1/$0})
learnOp(Op.BinaryOperation("+", +))
learnOp(Op.BinaryOperation("−"){$1-$0})
learnOp(Op.UnaryOperation("√", sqrt))
}
init() {
knownOps["×"] = Op.BinaryOperation("×", *)
knownOps["÷"] = Op.BinaryOperation("÷"){$1/$0}
knownOps["+"] = Op.BinaryOperation("+", +)
knownOps["−"] = Op.BinaryOperation("−"){$1-$0}
knownOps["√"] = Op.UnaryOperation("√", sqrt)
}
More Swift and
Foundation Frameworks
optional is enum
enum Optional<T> {
case None
case Some(T)
}
var x:String? = nil
x = Optional<String>.None
x = "hello"
x = Optional<String>.Some("hello")
var y = x!
switch x {
case .Some(let value):
y = value
case .None:
// raise an exception
break
}
playground的optional不再印出some
設定範圍的range
數字區間,
前後只能接數字
整數或浮點數皆可
struct Range<T : ForwardIndexType>
String.Index定區間
switch搭配range
for in 搭配range
此時range只能是整數
range搭配array
let array = ["a","b","c","d"]
let subArray1 = array[2...3]
let subArray2 = array[2..<3]
println("(subArray1[1]) (subArray2[0])")
String.Index
extension String : CollectionType {
/// A character position in a `String`
struct Index : BidirectionalIndexType, Comparable, Reflectable {
每個字佔據的記憶體⼤大⼩小不同
String.Index
String.Index
NSObject, NSNumber,
NSDate, NSData
type in Swift
class, struct, enum
reference type value type
改變屬性內容的
mutating function
適⽤用於value type的
struct & enum
防⽌止覆寫的final定型夜
• 防⽌止subclass or override
• for class, method, property ,subscript
型別⽅方法和屬性
宣告時須同時設定初始值
以static宣告
型別⽅方法和屬性
class Baby {
static var maxAge:Int = 100
static func cry(){
}
}
Baby.cry()
Baby.maxAge = 300
取消⾃自動產⽣生的
external name 利⽤用 _
⾃自動產⽣生的external name:
1. init的每個參數
2. ⽅方法裡的每個參數(第⼀一個參數除外,不包含function )
偵測屬性變更的
property observer
• 在property宣告裡定義willSet & didSet
• willSet將在屬性即將設定時被呼叫
• didSet將在屬性已設定時被呼叫
• 當初始化設定property時不會觸發
• 設定即觸發,即使設定⼀一樣的值
• 不適合let宣告的屬性
偵測屬性變更的
property observer
偵測屬性變更的
property observer
property observer的覆寫
讓屬性變懶的lazy咒語
⼀一定要初始化的
資料屬性
1. 利⽤用 =指派初始值,

初始值甚⾄至可由function或closure的結果指派


2. 宣告為optional,預設初始為nil
3. Initialization
初始化物件的⽅方法
initializer
⾃自動⽣生成的無參數 initializer
─ default initializer
接受參數的彈性 initializer
init參數⾃自動產⽣生同名的external name
利⽤用self區分age
不能再⽤用Baby()⽣生寶寶,因為沒有default initializer
但可另外再定義無參數的init()
失敗的failable initializer
init?
繼承和⻱⿔龜⽑毛的initializer
• 原則⼀一:

屬性的初始,必須在當初宣告屬性的類別裡進⾏行。
• 原則⼆二:

⼦子類別得先完成⾃自⼰己屬性的初始後,才能進⾏行⽗父類別
屬性的初始。
繼承和⻱⿔龜⽑毛的initializer
先初始⽗父類別的屬性
在⼦子類別初始⽗父類別的屬性
物件建⽴立的
兩階段初始化過程
物件建⽴立的
兩階段初始化過程
designated initializer &
convenience initializer
convenience initializer和
designated initializer的呼叫規則
initializer的繼承
• 情況⼀一:

若⼦子類別沒有定義任何 designated initializer,它將繼
承⽗父類別的 designated initializer。
• 情況⼆二:

如果滿⾜足情況⼀一,或⼦子類別覆寫了⽗父類別所有的
designated initializer,它 將繼承⽗父類別的
convenience initializer。
initializer的繼承
initializer的繼承
initializer的繼承
initializer的繼承
initializer的繼承
struct的
memberwise initializer
struct的
memberwise initializer
在struct裡⾃自訂init,Swift將不再好⼼心地⾃自動⽣生成memberwise initializer
關於型別的兩三事
成為最有型的型別⼤大師
化⾝身任意型別的變⾊色⻯⿓龍
Any和AnyObject
@objc protocol AnyObject {
}
typealias Any = protocol<>
化⾝身任意型別的變⾊色⻯⿓龍
Any和AnyObject
⾨門不當⼾戶不對的型別問題
強制轉型的as!
說謊轉型 -> crash
var number1:Any = 18
var number2 = number1 as! String
nil強制為有資料 -> crash
crash
as! & as
向下轉型 向上轉型
型別⽐比較的is
繫緊安全帶轉型的as?
轉型後將變成optional
as?和if
as!和for
class Baby {
func cry() {
}
}
var babyArray:[AnyObject] = [Baby(), Baby()]
for baby in babyArray as! [Baby] {
baby.cry()
}
注意: Any轉型會crash
struct Baby {
func cry() {
}
}
var babyArray:[Any] = [Baby(), Baby()]
for baby in babyArray as! [Baby] {
baby.cry()
}
as和switch
不管⽐比較對象是否為optional,都以as⽐比對
assertion
release的版本不會crash,assert將被忽略,只有debug版會
func assert(condition: @autoclosure () -> Bool, _ message:
@autoclosure () -> String = default, file: StaticString = default,
line: UWord = default)
1. @autoclosure
2. 呼叫function時,有預設值的參數可省略
func validation() -> String? {
return "Pass"
}
assert(validation() != nil, "the validation function returned nil")
結果為false時,程式將crash
@autoclosure
適⽤用情境: 傳⼊入的closure參數只有⼀一⾏行時,省略 { }
條件:
1. closure必須沒有接受任何參數
2. closure執⾏行的程式碼只能有⼀一⾏行
通吃型別的generic
沒有generic的史前世界
通吃型別的generic
設定型別條件
advanced function
filter
map
reduce
sort
splice

Standford 2015 iOS讀書會 week2: 1. Applying MVC 2. More Swift and Foundation Frameworks