import UIKit
class ViewController: UIViewController {
@IBOutlet weak var display: UILabel!
var userIsInTheMiddleOfTypingANumber: Bool = false
@IBAction func appendDigit(sender: UIButton) {
let digit = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber{
display.text = display.text! + digit
}else{
display.text = digit
userIsInTheMiddleOfTypingANumber = true
}
println("digit = \(digit)")
}
}
上のコードのUILabel!をUILabel?にしても、Optionalである。
だが、エラーが出る。
そこで、display.textをdisplay!.textにすると、エラーが治る。
これはどういうことだろうか。
ここに詳しい説明が載っている。
つまり、!を使っていた場合は「暗黙的なOptional」を使っていたのである。暗黙的であるため、自動的にUnwrapされていたわけだ。
?に変えたことによって、明示的なOptionalに変わったため、display!.textの!が必要になったのである。
コードは以下のようになった
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var display: UILabel?
var userIsInTheMiddleOfTypingANumber: Bool = false
@IBAction func appendDigit(sender: UIButton) {
let digit = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber{
display!.text = display!.text! + digit
}else{
display!.text = digit
userIsInTheMiddleOfTypingANumber = true
}
println("digit = \(digit)")
}
}
では、コードを戻しておこう。
前の回の続きなので、3ボタンを複製してEnterキーを作ろう。
Edit→Emoji&Symbolsでenterを入れると、Enterが出てくるので、それを使おう。
次にこれをAction接続する。Name:enterで、ArgumentはNoneだ。
そうすると、Enterが文字盤に出てしまう。なので、EnterのappendDigitに対する接続を切っておこう。
以下のような図になる。
では、以下のコードをプロパティに加えよう
var operandStack:Array<Double> = Array<Double>()
これは、ジェネリック型の一つで、Doubleを要素とした配列を構成する。= Array()で初期化をしないとエラーが出る。
これで全部のコードは以下のようになる。
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var display: UILabel!
var userIsInTheMiddleOfTypingANumber: Bool = false
@IBAction func appendDigit(sender: UIButton) {
let digit = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber{
display.text = display.text! + digit
}else{
display.text = digit
userIsInTheMiddleOfTypingANumber = true
}
println("digit = \(digit)")
}
var operandStack:Array<Double> = Array<Double>()
@IBAction func enter() {
userIsInTheMiddleOfTypingANumber = false
}
}
operandStackに表示された値を入力するために以下のようにします
@IBAction func enter() {
userIsInTheMiddleOfTypingANumber = false
operandStack.append(display.text!)
}
するとエラーが出ますね。operandStackはDoubleなのに対し、display.text!はStringだからです。
そこで、以下のようにします
@IBAction func enter() {
userIsInTheMiddleOfTypingANumber = false
operandStack.append(self.displayValue)
println("operandStack = \(operandStack)")
}
var displayValue: Double {
get{
return NSNumberFormatter().numberFromString(display.text!)!.doubleValue
}
set{
display.text = "\(newValue)"
userIsInTheMiddleOfTypingANumber = false
}
}
getの方ではNSNumberFormatter()のnumberFromStringによってdisplay.textをdoubleに変えていますね。
setの方では、display.text = "(newValue)"によって、doubleをStringに変えてdisplay.textに代入しています。
次に、✖️ボタンをつけて、Action接続します。typeはUIButtonでやります。
appendDigitへの接続は切っておくことですね。
以下のようなコードになりました
@IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber {
enter()
}
switch operation {
case "×":
if operandStack.count >= 2{
displayValue = operandStack.removeLast() * operandStack.removeLast()
enter()
}
// case "÷":
// case "+":
// case "−":
default: break
}
}
これで✖️が実装できましたね。8 Enter 9 ✖️ で、演算ができるので確かめてみてください
operandStack = [8.0, 9.0]
operandStack = [72.0]
これを四則演算全て実装するのはかなり冗長なので、以下のように書き換えました。
@IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber {
enter()
}
switch operation {
case "×":performOperation(multiply)
// case "÷":
// case "+":
// case "−":
default: break
}
}
func performOperation(operation: (Double,Double) -> Double){
if operandStack.count >= 2{
displayValue = operation(operandStack.removeLast(), operandStack.removeLast())
enter()
}
}
func multiply(op1: Double,op2: Double) -> Double{
return op1 * op2
}
performOperationメソッドの引数が、メソッドになっていますね。
これも8 Enter 95 ✖️で演算できるので試してください
operandStack = [8.0, 95.0]
operandStack = [760.0]
ただ、これもdivideとかaddとかの演算のメソッドを加えていくのはかなり冗長なので、これも工夫していく必要があります。
ここでクロージャーを使います。
@IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber {
enter()
}
switch operation {
case "×":performOperation({(op1,op2) in return op1 * op2})
// case "÷":
// case "+":
// case "−":
default: break
}
}
このようにしても動きますね。
@IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber {
enter()
}
switch operation {
case "×":performOperation({(op1,op2) in op1 * op2})
// case "÷":
// case "+":
// case "−":
default: break
}
}
このようにreturnを削除しても動きます
@IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber {
enter()
}
switch operation {
case "×":performOperation({ $0 * $1})
// case "÷":
// case "+":
// case "−":
default: break
}
}
$1 * $2にしても動きます。
@IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber {
enter()
}
switch operation {
case "×":performOperation(){ $0 * $1}
// case "÷":
// case "+":
// case "−":
default: break
}
}
関数部を外に出しても動きますね
@IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber {
enter()
}
switch operation {
case "×":performOperation{ $0 * $1}
// case "÷":
// case "+":
// case "−":
default: break
}
}
()のかっこもいらないですね。
@IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber {
enter()
}
switch operation {
case "×":performOperation{ $0 * $1}
case "÷":performOperation{ $1 / $0}
case "+":performOperation{ $0 + $1}
case "−":performOperation{ $1 - $0}
default: break
}
}
全ての演算に関して実装しました。"÷","−"については順序が逆になるんですね。
現時点での全体的なコードは以下のようになります
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var display: UILabel!
var userIsInTheMiddleOfTypingANumber: Bool = false
@IBAction func appendDigit(sender: UIButton) {
let digit = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber{
display.text = display.text! + digit
}else{
display.text = digit
userIsInTheMiddleOfTypingANumber = true
}
println("digit = \(digit)")
}
@IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber {
enter()
}
switch operation {
case "×":performOperation{ $0 * $1}
case "÷":performOperation{ $1 / $0}
case "+":performOperation{ $0 + $1}
case "−":performOperation{ $1 - $0}
default: break
}
}
func performOperation(operation: (Double,Double) -> Double){
if operandStack.count >= 2{
displayValue = operation(operandStack.removeLast(), operandStack.removeLast())
enter()
}
}
var operandStack:Array<Double> = Array<Double>()
@IBAction func enter() {
userIsInTheMiddleOfTypingANumber = false
operandStack.append(self.displayValue)
println("operandStack = \(operandStack)")
}
var displayValue: Double {
get{
return NSNumberFormatter().numberFromString(display.text!)!.doubleValue
}
set{
display.text = "\(newValue)"
userIsInTheMiddleOfTypingANumber = false
}
}
}
では、次にルートの記号を加えてみます
@IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber {
enter()
}
switch operation {
case "×":performOperation{ $0 * $1}
case "÷":performOperation{ $1 / $0}
case "+":performOperation{ $0 + $1}
case "−":performOperation{ $1 - $0}
case "√":performOperation{ sqrt($0)}
default: break
}
}
エラー出ますね。performOperationの引数が二つあるのに、使っている値が一つしかないからです。
なので、performOperation関数をコピーして以下のような関数をオーバーロードします。
func performOperation(operation: Double -> Double){
if operandStack.count >= 1{
displayValue = operation(operandStack.removeLast())
enter()
}
}
Method 'performOperation' with Objective-C selector 'performOperation:' conflicts with previous declaration with the same Objective-C selector
上のようなエラーが出るので、片方または両方にprivateをつける。
private func performOperation(operation: (Double,Double) -> Double){
if operandStack.count >= 2{
displayValue = operation(operandStack.removeLast(), operandStack.removeLast())
enter()
}
}
func performOperation(operation: Double -> Double){
if operandStack.count >= 1{
displayValue = operation(operandStack.removeLast())
enter()
}
}
完成ですね。ちゃんと動くと思います。
Costraintsを設定してやって,UpdateFrameをかけてやれば、ちゃんとUIいっぱいに設定されます。
最終的にできたコードは以下のようになります
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var display: UILabel!
var userIsInTheMiddleOfTypingANumber: Bool = false
@IBAction func appendDigit(sender: UIButton) {
let digit = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber{
display.text = display.text! + digit
}else{
display.text = digit
userIsInTheMiddleOfTypingANumber = true
}
println("digit = \(digit)")
}
@IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber {
enter()
}
switch operation {
case "×":performOperation{ $0 * $1}
case "÷":performOperation{ $1 / $0}
case "+":performOperation{ $0 + $1}
case "−":performOperation{ $1 - $0}
case "√":performOperation{ sqrt($0)}
default: break
}
}
private func performOperation(operation: (Double,Double) -> Double){
if operandStack.count >= 2{
displayValue = operation(operandStack.removeLast(), operandStack.removeLast())
enter()
}
}
func performOperation(operation: Double -> Double){
if operandStack.count >= 1{
displayValue = operation(operandStack.removeLast())
enter()
}
}
var operandStack:Array<Double> = Array<Double>()
@IBAction func enter() {
userIsInTheMiddleOfTypingANumber = false
operandStack.append(self.displayValue)
println("operandStack = \(operandStack)")
}
var displayValue: Double {
get{
return NSNumberFormatter().numberFromString(display.text!)!.doubleValue
}
set{
display.text = "\(newValue)"
userIsInTheMiddleOfTypingANumber = false
}
}
}