月別アーカイブ: 2018年12月

【Swift4】機器がiPhoneかiPadかを判定。画面サイズでも判定。

参考サイト
【Swift4】iPhone・iPadなどの機種判定し処理を振り分ける方法【iOS9】 | ニートに憧れるプログラム日記

上記ページでもSwift4と書かれているが自分の環境ではうまく行かなかったので、試行錯誤した。
UIDevice.current.model で取得できるようだ。
あと、appleTVとcarPlayの場合何を返すのか確定できなかったので割愛した。

更に画面サイズで、細かいサイズ判定ができる。
画面が縦向きか横向きかで高さが変わるのでそれも考慮。

機種も変数で返してくれたら良いのになー。
うじゃうじゃ。

追記。
google Analytictから吐き出されるログを見てたら

“&dm” = “iPhone10,3″;
“&ds” = app;
“&sr” = 1125×2436;
“&t” = screenview; 

とゆーぶぶんが。
なんかで判定はできるんやろな。
うじゃうじゃ。

追記。2018/12/24
[iOS][Android][Tips] デバイスモデル名を取得する | DevelopersIO
上記サイトを見ると、C 言語のライブラリ関数である utsname を使用 するとわかるそうですが、
私には何のことかよくわかりませんでした。/(^o^)\

【Swift4】【autoLayout】レイアウトが決まってからの変更処理のタイミング

「autoLayoutってなんじゃー!つかいもんにならんわー!」
と、そんなふうに思っていた時期が僕にもありました。(笑)

使い慣れてみるとケッコー便利です。\(^o^)/

さて、そんな便利なautoLayoutですが、一つ困ったことが。
画面のサイズが決定して、それをもとに%などでサイズが決まって形状を変えたいときなどどの段階で処理するかが問題なのです。

viewControllerで描画に関連しそうなメソッドのライフサイクルはこんな感じかな?

さて、autoLayoutでのレイアウトが決定しているのがviewDidLayoutSubviews以降です。
それ以前は値が決定しておらず、autoLayoutで決まる値を参照にするとおかしなことになる可能性が高いです。

viewDidLayoutSubviewsを知る前はviewDidAppearにその処理を書いていました。
しかし、ビューが描画されたあとなので、一瞬描き変えられるところが見えたりします。/(^o^)\

また、毎回他のビューから戻ってきてビューが表示されるたびに同じ処理を繰り返してしまいます。
レイアウトが決まってビューが表示される直前のviewDidLayoutSubviewsなら描き変えられるところは表示されませんが、
こちらはビューの切り替わりだけでなくビューが回転したりイベントあるたびに呼ばれてしまうようです。

で、本題。
結局やりたいのはviewDidLayoutSubviewsで一回だけ処理をさせるということ。
いろいろと調べてこちらのサイトが参考になりました。

[Swift] viewDidLayoutSubviewsで初回だけ処理をしたい | 黒ごまのおむすび

Lazyというのをつかうらじいです。/(^o^)\

この処理だとビューの表示前に一回だけ呼び出すことができました。
他の人はこんな場合どうしているんだろう?
うじゃうじゃ。/(^o^)\

【Swift4】【CallKit】CXCall、電話の発着信等を取得する。

電話の着信時、受話時、終話時をアプリで受け取りたかったので調べてみた。
参考サイト

Xcode|iOS10から新しく加わったCallkitを使って通話の状態を取得してみた

上記サイトが役に立ちました。
ただ、Objective-cだったのでSwiftに変更。

CallKitのCXCallObserverのデリゲートでCXCallの値で送られてくるようだ。

CXCall – CallKit | Apple Developer Documentation
デベロッパサイトを見てgoogle翻訳

var uuid:UUID
コールの一意の識別子。
(よくわからん、とりあえず無視の方向で。w)

var isOutgoing:Bool
呼び出しが発信かどうかを示すブール値。
(コールが発信中か受信中か?)

var hasConnected:Bool
呼び出しが接続されているかどうかを示すブール値。
(通話中かどうか?)

var hasEnded:Bool
呼び出しが終了したかどうかを示すブール値。
(通話が終了したかどうか。)

var isOnHold:Bool
通話が保留状態かどうかを示すブール値。
(保留中?)

状態の変化があったときこれらの組み合わせで通知が来るようだ。
ちょっとややこしい。

とりあえずアプリで受けたいのは「着信」「受話」「終話」
なので下記のような感じで試してみた。

これで、家電からiPhoneに電話。「着信」「受話」「保留」「保留解除」「終話」と、「着信」から受けずに電話を切って「終話」。とやってみた。

まず着信
  通知があったよ!
  isOutgoing false
  hasConnected false
  hasEnded false
  isOnHold false

すべてfalseの通知が来ます。

続いてそこから電話を受けます。
  通知があったよ!
  isOutgoing false
  hasConnected true
  hasEnded false
  isOnHold false

保留にします。
  通知があったよ!
  isOutgoing false
  hasConnected true
  hasEnded false
  isOnHold true

保留を終わります。
  通知があったよ!
  isOutgoing false
  hasConnected true
  hasEnded false
  isOnHold false

電話を切ります。
  通知があったよ!
  isOutgoing false
  hasConnected true
  hasEnded true
  isOnHold false

もう一度着信は同じなので割愛して、電話を受けずに切った場合。
  通知があったよ!
  isOutgoing false
  hasConnected false
  hasEnded true
  isOnHold false

こうして見ると、hasConnectedだけでは「電話に出たとき」か「通話の終了」の通知かはわからず、hasEndedを含める必要があるのがわかります。
あ、しかも、これじゃ、着信から電話に出たのか、保留から電話にもどったかわからないじゃん。/(^o^)\
そこを区別するにはこちら側でなにか記録して区別するしか無いですね。

ところで、iPhoneの保留ってどうするか知ってますか?
試そうと思って家電からiPhoneに受話してみたが、保留の機能が見つからない!/(^o^)\
仕方ないので一旦切って調べてみると、「消音」の長押しだそうだ。
試そうと思って家電からiPhoneに受話してみたが、長押ししてみても保留にならない!/(^o^)\
仕方ないので一旦切って調べてみると、「消音」の3秒位長押しだそうだ。
そしてもういっかい試してみたらちゃんとできました。/(^o^)\
古い情報だと保留中は電子音とか書いてありますが、先程試した時は日本語で「保留中ですお待ち下さい」から音楽になっていました。
あと、通話中のスクリーンショットを撮ろうと思ったのですが、
通話する、「音量UP+サイドキー」を押すで、電話が切れる!/(^o^)\
タイミング悪かったかなと再度通話する、「音量UP+サイドキー」で、電話が切れる!/(^o^)\
どうも通話中はスクリーンショットが撮れないようです。
ちなみに画面収録も着話したら録画が切れました。通話中は記録できないようです。
なんかすっごい電話代無駄にした気がする。/(^o^)\

閑話休題/(^o^)\それはさておき、

形にしてみよう。
受話状態になったらこれを参考に
【Swift4】NotificationCenterの備忘録。 | iPhoneアプリ備忘録
通知が来るようにしてみた。

メイン画面にはLabelを。

電話を通知する方のクラス。

こんな感じで実現できました。\(^o^)/
GitHubが使えればコードをアップできるらしいけどよくわかんないんだよね。/(^o^)\

【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処理を入れてみた。
(下記参照)

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

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

こんな感じ。

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

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