2019年7月31日水曜日

12口のタワータップが便利すぎる件

コンセント周りが非常にカオスになっていたので、先日のAmazon Prime Dayで、12口のタワータップを購入してみました。

でつないだ結果がこちら(除菌アルコールは無視してくださいw)。



まだぐちゃぐちゃしてそうですが、これでも整理できた感じ。

これまで電源タップ2つでつないでいたものが1つになるので非常に助かります。しかも無停電電源装置と接続しているので、急な停電にも対応可能です。


Amazon上では販売業者がコロコロ変わるので、いつまで有効かわかりませんが、製品はこちらになるかと思います。



おすすめです。

2019年7月27日土曜日

delegate関係のXCodeのバグ

delegateを実装しているとXCodeのバグにいくつか出会いました。

(1)プロトコルの実装
まず、プロトコルを採用したクラスでのこと。プロトコルで定義した関数を実装してもグリーンにならず白いままで、クラス部分には「プロトコルの関数実装してねーだろ」と出ます。

しかし、どう見てもスペルミスはない。悩んでエラーメッセージをクリックすると、なんとFixボタンが出てきてボタンを押すと、勝手に関数が表示されます。

しかたないので、関数の記述をそちらに移すとエラーは無くなりました。

どうやら、プロトコルの関数を手動で実装すると認識してくれない場合があるようです。

(2)関数の利用
おそらく同じ起源のバグと思われますが、関数を利用する側でも起こります。 delegate設定したオブジェクトの関数を認識してくれません。上記(1)でうまく言っていない場合もありますが、(1)で問題を解決しても、オブジェクトと関数は白いまま、という場合もあります。
そんなときは、一旦記述を消してから、表示されるガイドから関数を選択してあげるとうまくいきます。


ということで、Apple社内でもあまりデリゲートは使われていないのかもしれませんが、そんなバグがあったので気をつけてください。


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牧場ですね。

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