【Swift4】【UIDatePicker】のバグふたたび。UIDatePickerMode .countDownTimer

Swiftには、いや、Xcodeにはバグが有る。
2年前にもObjective-Cで泣かされた。
その時はなんとかなったけどそのバグはSwiftになっても直ってなかった。
とゆーか、よりひどくなってた。

そのバグはUIDatePickerのcountDownTimerモードにある。
マイナーすぎて使い所無い機能なのか、それ自体の情報も少ない。

UIDatePickerのcountDownTimerモードというのは、その名の通り、
24時間までのカウントダウンの時間を設定するためのピッカーだ。
ピッカーで10分と設定すると600秒の値が渡される。

さて、そのバグというのはピッカーで数値を決めても一回目のときはスルーされてしまうとゆーものだ。
二回目以降はちゃんとデータが渡されるのだが、一回目はスルーされてしまう。
10分を選んでも全然反映されない。
そのため、例えば10分に設定したい時は、一度11分にしてから10分にするなどというとてもめんどくさいことになる。
そんな状態ではとてもリリースできたものではない。

ネットを調べてみるといくつか情報はある。
古いのはこちら。
ios – UIDatePicker bug? UIControlEventValueChanged after hitting minimum internal – Stack Overflow
どうもiOS7の頃からあるバグらしい。
一応解決策も提示してあり、僕も2年くらい前にお世話になった。
割りと最近の記事ではこちら。
Xcode – DatePickerの値選択時の表示エラーが直らない|teratail
こちらはswift3での解決策が示してある。ま、Objective-cからSwiftに変わっただけでやってることは同じ。

そちらを参考にしてピッカーのモードをカウントダウンタイマーにしたあと、
バグ回避のためDispatchQueue処理を入れてみた。
(下記参照)

//キーボードをピッカーにする
    func keybordSetUp() {
        timeText.delegate = self as? UITextFieldDelegate
        //テキストフィールドのキーボードをdatePickerにする
        timeText.inputView = datePicker
        //ピッカーのモードをカウントダウンタイマーに
        datePicker.datePickerMode = UIDatePickerMode.countDownTimer
 
        //バグ回避のためDispatchQueue
        DispatchQueue.main.async {
//            self.datePicker.countDownDuration = (初期値)
            self.datePicker.countDownDuration = TimeInterval(self.countDownSetValue)
        }
        
        //ピッカーの値の通知先を設定。
        datePicker .addTarget(self,
                              action: #selector(self.datePickerValueChanged),
                              for: UIControlEvents.valueChanged)
    }
    
 //ピッカーの値を反映
    @objc func datePickerValueChanged() {
        
        print("カウントダウンピッカーがまわったよ")
        downCountTime = 0
        countDownSetValue = Int(datePicker.countDownDuration)
        count = Int(datePicker.countDownDuration)
        
        let hh = Int(count/(60*60))
        // doubleで余りを出す計算をするときはfmod
        let mm = Int(fmod(Double(count/60),60))
        let ss = Int(fmod(Double(count),60))
        timeText.text = String(format: "%02d:%02d:%02d", hh, mm, ss)
    }

自分だけなのか、Swift4以降の仕様なのかこの状態ではやはり一回目の設定はスルーされた。
半日ほど試行錯誤したがどうしてもうまくいかない。
そんな中、キーボードを仕舞ってまたキーボードを出したときもまた同じく一回目がスルーされていることに気づく。

そうであれば、キーボードが出たときにバグの回避処置を入れればなんとかなるのでは無いか。
とゆーことで、ノーティフィケーションをつかい、キーボードが出たときに回避処置が入るようにしてみた。

こんな感じ。

    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
  (中略)
        //キーボードが出たとき(UIKeyboardDidShow)に通知する。
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(self.showKeyBoard(notification:)),
            name: NSNotification.Name.UIKeyboardDidShow,
            object: nil
        )
    }


    @objc func showKeyBoard(notification: Notification) {
        print("キーボードが出た")
        DispatchQueue.main.async {
            //            self.datePicker.countDownDuration = (初期値)
            self.datePicker.countDownDuration = TimeInterval(self.countDownSetValue)
        }
    }

結果は見事成功!\(^o^)/
なんとかカウントダウンのピッカーが使えるようになった。

時期に忘れてしまうと思うので備忘録として残しておく。/(^o^)\
あと、誰かの参考になったら嬉しい。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です