2019年7月24日水曜日

電卓画面の実装とデリゲートによる値の受け渡し

いよいよ電卓画面を実装します。

ViiewControllerからキーボードの値だけをNumberQueueオブジェクトに入れ込めば済むように作ってある(ハズな)ので、本当に画面を作るだけで済むはずです。

で、できあがった画面は次のものになります。



なかなか真っ暗でしょ(ww)


まぁ色合いはさておき、下のボタン類をNumberQueueに受け渡すところは簡単にできました。単にイベントを受け取ったら所定の値を渡すだけです。
    @IBAction func AC(_ sender: Any) {
        numberQueue.calc("c")
    }
    @IBAction func c(_ sender: Any) {
        numberQueue.pop()
    }
    @IBAction func nine(_ sender: Any) {
        numberQueue.push("9")
    }
    @IBAction func eight(_ sender: Any) {
        numberQueue.push("8")
    }
    @IBAction func seven(_ sender: Any) {
        numberQueue.push("7")
    }
    @IBAction func six(_ sender: Any) {
        numberQueue.push("6")
    }
    @IBAction func five(_ sender: Any) {
        numberQueue.push("5")
    }
    @IBAction func four(_ sender: Any) {
        numberQueue.push("4")
    }
    @IBAction func three(_ sender: Any) {
        numberQueue.push("3")
    }
    @IBAction func two(_ sender: Any) {
        numberQueue.push("2")
    }
    @IBAction func one(_ sender: Any) {
        numberQueue.push("1")
    }
    @IBAction func zero(_ sender: Any) {
        numberQueue.push("0")
    }
    @IBAction func zerozero(_ sender: Any) {
        numberQueue.push("0")
        numberQueue.push("0")
    }
    @IBAction func dot(_ sender: Any) {
        numberQueue.push(".")
    }
    @IBAction func plus(_ sender: Any) {
        numberQueue.calc("+")
    }
    @IBAction func minus(_ sender: Any) {
        numberQueue.calc("-")
    }
    @IBAction func x(_ sender: Any) {
        numberQueue.calc("*")
    }
    @IBAction func dev(_ sender: Any) {
        numberQueue.calc("/")
    }
    @IBAction func equal(_ sender: Any) {
        numberQueue.calc("=")
    }
    

問題は、結果を表示するところです。

NumberQueueオブジェクト自身は計算結果を返してくれません。値を返してもいいのですが、そうするとボタンごとに結果を表示するという、変な話になってしまいますので、それではNGです。

ということで、delegateを実装していくことにしました。前にも作っていましたが、objective-cでもあり、もう忘れているのもあり、調べながら作っていきました。

まずはプロトコロル(空の関数)の実装からです。
protocol DisplayDelegate{
    func disp(_ s:String)
}

この空の関数を定義するのは、ViewControllerですので、このDelegateを採用しますよ、というのをViewControllerで宣言してあげます。
class ViewController: UIViewController ,DisplayDelegate{

そうすると、「ViewControllerにこの関数を実装していませんよ」と怒られますので、実装してあげます。
    func disp(_ s: String) {
            print(s)
            mainDisplay.text = s
    }

print(s)は単にデバック用の表示です。

ViewConroller側はこれでOK(ではありません。あとで問題になります)。

NumberQueue側では、このデリゲート使いますよ、というのを宣言します。
    var display: DisplayDelegate!

この!は、デリゲートができていない場合nilになるので、!を書くようですが、これ自身に問題がありませんが、あとで問題に。

で、このデリゲートオブジェクトの関数を直接使ってもいいのですが、使うための関数を作ってあげます。

    func disp(_ s:String){
        self.display.disp(s)
    }


これで実装は完了(のはずでしたが・・)ですので、これまでデバッグ用に実装していた結果の表示のprintをdispに置き換えてあげると表示されるはずでした。

しかし、実行時にエラーが。
unexpectedly found nil while implicity unwrapping an optional value

なんじゃこれ、というので調べてみると!を?にして関数にも?をつければいいという、デマ回答が乗っていてさらに混乱しました。

いろいろとググっていくと、質問者の質問に「何かを実装していないけれども、実装していると仮定して」とかいう前提付きで回答している人がいました。

これは意地悪な回答だわ、と思いつつ、そういえばViewConroller側ではNumberQueueから呼び出されるのがわからないし、このdisplayというオブジェクトが生成されていないということなんだよなぁ、ということでこんなコードを入れてみました。

    override func viewDidLoad() {
        
        super.viewDidLoad()
        
        numberQueue.display = self

        // Do any additional setup after loading the view.

        
    }

はい、ビンゴです。

numberQueueのdisplayというオブジェクトは、自分が実装してますよ、と言ってあげているんですね。これで上のエラーがでなくなりましたので、無事displayのオブジェクトができてViewControllerで受け取ることができました。

しかし、delegateの解説が少なすぎて、あっても複雑に書かれすぎでよくわからんわ。まぁ解決したのでOK牧場ですね。

あとは、この電卓をつかいながらデバッグしていきます。







0 件のコメント: