105
Standford 2015 iOS讀書會 week2 彼得潘 1. Applying MVC 2. More Swift and Foundation Frameworks

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

  • Upload
    -pan

  • View
    567

  • Download
    0

Embed Size (px)

Citation preview

Standford 2015 iOS讀書會 week2

彼得潘

1. Applying MVC 2. More Swift and Foundation Frameworks

Applying MVC

MVC

Model: 計算機

create new class

檔名沒有強制要跟類別名⼀一樣

名稱

其它名稱: 每個單字的字⾸首⼤大寫,但第⼀一個單字的字⾸首⼩小寫

type名稱: 每個單字的字⾸首⼤大寫

儲存operand & operationvar 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

⾃自訂能⼒力的operatorinfix, 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 enumenum 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 initializerinit?

繼承和⻱⿔龜⽑毛的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!和forclass 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. @autoclosure2. 呼叫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