Swiftで遊ぼう! - 676 - More Swift and Foundation Framework 2
- Swiftで遊ぼう!の前書き-> Life-LOG OtherSide
- Swift2.1 & Xcode7.1対応の日本語版アップルチュートリアル!
- Table View実装チュートリアルをXcode7.3で解説
- Core Data シンプルチュートリアル
- 私の本業、オフィシャルなブログ-> Life-LOG
講義3は文法的な説明が続きました。そして最後にPropertyListの説明とAniyObjectの関係の説明です。なんとなくぼんやりと考えていたPropertyListをCalculatorデモに組み込みます。
Developing iOS 9 Apps with Swift - Free Course by Stanford on iTunes U
計算結果を「save」して、後でその結果を「restore」する機能を組み込むのだと最初は思いました。そうじゃ無かったんです。program自体、計算式を「save」、例えば「3 × 7 + 6」という計算自体を「save」するという実装です。したがって、「restore」すると言うことは、「save」されている計算式を再計算させるという考え... うーん、こういう考え方は思いつきもしませんでした。この計算式をAnyObjectの集合体(DoubleとStringの混在だからです)として保存するんです。
var program: AnyObject
これはprivateではなくpublic(internalのことです)にしてアクセスできるようにしてます。ここでドキュメンテーションという考え方から、「typealias」を使って、PropertyListでありながらAnyObjectであることを明白にします。
typealias PropertyList = AnyObject var program: PropertyList
programは計算型プロパティとして使用します。
var program: PropertyList { get{ // Coding... } set { // Coding... } }
どうして計算型にするかと言えば、もう1つのprivateで外から見えないprogramを用意するからです。
それはinternalProgramとして用意します。これは「AnyObject」の集合体として用意するんです。プログラムのステップを保存する(こういうちょっとした保存はPropaertyList
として用意します。
private var internalProgram = [AnyObject]()
internalProgramで計算のステップを次々に記録させていきます。自動で記録をさせるために「setOperand()」と「performOperation()」メソッドの両方に加えます。
// operandを押すとスタックに組み込まれます。 func setOperand(operand: Double) { accumulator = operand internalProgram.append(operand) // 追加 } ... func performOpeation(symbol: String) { internalProgram.append(symbol) // 追加 if let operation = operations[symbol] { switch operation { case .Constant(let value): accumulator = value case .UnaryOperation(let function): accumulator = function(accumulator) case .BinaryOperation(let function): executePendingBinaryOperation() pending = PendingBinaryOperationInfo(binaryFunction: function, firstOperand: accumulator) case .Equals: executePendingBinaryOperation() } } }
これで自動的に計算ステップ(プログラム)が記録されていきます。そしてこれを外部から参照するために変数programを使って、コピーを扱うので計算型プロパティの「get」はシンプルに次のようになります。
var program: PropertyList { get{ return internalProgram } set { // Coding... } }
次は「set」です。internalProgramの値は次次と新しい値が加わっているので、保存していた[AnyObject]に再び計算をさせたい場合は、internalProgramを空にして、新しい[AnyObject」のデータで再計算させて、internalProgramを置き換えてやる必要があります。次のようにします。
set { self.clear() if let arrayOfOps = newValue as? [AnyObject] { for op in arrayOfOps { if let operand = op as? Double { setOperand(operand) } else if let operation = op as? String { performOpeation(operation) } } }
まず「clear()」メソッドはカスタムメソッドです。これは後でコードしますが、internalProgramを空にして計算をリセットするステップです。そして「newValue」はを[AnyObject]にキャストして、それぞれの項目でDoubleかStringで判断してメソッドを実行すれば、再計算がされながらinternalProgramにもセットされます。
clear()メソッドは簡単に次のように用意します。
func clear() { accumulator = 0.0 pending = nil internalProgram.removeAll() }
これでCalculatorBrainの実装は終了です。
次はMain.storyboardに移って、左済みの2つのボタン「e」と「cos」そそれぞれ「save」と「restore」にします。performOperation()メソッドに繋がっているので「右 + クリック」でコネクションを切ります。その後にViewControllerのコード内にそれぞれ「save()」と「restore()」メソッドを「Ctrl + ドラッグ」で作ります。
まず、CalculatorBrainで自動的に記録しているinternalProgramの内容を記録する変数を用意します。
var savedProgram: CalculatorBrain.PropertyList?
「save」ボタンが存在するまで必要ないのでオプショナルにします。そして「save」ボタンを押した時に、この変数にCalculatorBrainのpragramを読み込めばいいわけです。
@IBAction func save() { savedProgram = brain.program }
そしてrestoreするときは逆です。保存したプログラムをCalculatorBrainのprogramにセットすればいいんです。計算が実行されるので、表示用にresultも読み込み直す必要があります。
@IBAction func restore() { if savedProgram != nil { brain.program = savedProgram! displayValue = brain.result } }
これで完璧です。ランします。ポートレイトでは「restore」ボタンが崩れるのでランドスケープにします。
これでCalculatorデモは終了です。今回はポール先生の説明していることが全て理解できました。まだ宿題(アサインメント)はしていないのですが、時間ができたらトライします。まずは授業についていかないといけないので明日から講義4に入ります。
今日はここまで。