ビギグラマーのノート

自作PCやプログラミングについてのブログです。

【Swift3】吹き出しを作る

 制作意図

 アプリケーションの初回起動などで吹き出しを使って機能を説明したい時があります。しかしデフォルトの吹き出し等が用意されていないので、今回balloonViewというカスタムビューを作成しました

f:id:BegiGrammer:20170602094059p:plain

コード

 BalloonView.swift with initializer

こっちがイニシャライザを使って綺麗に整えたやつ。動かせる機能はオミットされた。

BalloonView.swift Old Version

グリグリと動かせるけどあまり推奨しないし、意味がない。

解説

 やっていることはCoreGraphicsを使って吹き出しのイメージをBalloonViewに貼り付け。そしてその吹き出しの真ん中にUITextLabelを貼り付けているだけです。本当はもじもCoreGraphicsを使って吹き出しのイメージに書き込もうかと思いましたが、拡張性を考え今回このような形にしました。なのでラベル以外にもボタンなどを、吹き出しの中心であるcenterPointプロパティで位置決めして使うことができます。

 また四角形の形をCGRectで指定し、CGPointで頂点つまり吹き出しの三角のところを決めると自動でこれらの吹き出しを生成します。

f:id:BegiGrammer:20170603140031p:plain

 halfBaseLengthプロパティで吹き出しの三角形の底辺の大きさを変更することができます。上の図では赤と青の点の距離を示します。

 使用例のViewControllerでは吹き出し部分をグリグリとタッチで動かせるようになっていますが、静的な部分も毎回描写し直しているので効率はとても悪いです。実証用に付け足した機能なので実装する際は使用しないでください。

 使用するとUIImageViewとBalloonViewの二枚のSubViewがかぶさることになります。そうすると親のViewへの操作が一切受け付けなくなります。親への操作の透過についてこの2枚のsubViewのisUserInteractionEnabledfalseにしてください。

【Swift3】<Error>: CGContextClosePath: no current point.

No Current Point

  SwiftでCoreGraphicsを触っている時にこのような実行時エラーに遭遇しました。

f:id:BegiGrammer:20170528203441p:plain

 一見問題なく描写が済んでいるものの「現在のポイントではない」という誠に不親切なことが書かれており、一瞬無視しそうになりましたが怒られるので治しときましょう。

目次作るほどでもないSolution 

 このエラーはいくつかの問題によって発生するそうですが、私の場合はfillPath()で塗りつぶすのをclosePath()の前に置いたことで発生しました。つまりその順序を逆にしたところ解決しました。

円を描写する時

 円を描写する時にも同様のエラーに遭遇する時があります。で、これがエラーの出ない円を描写する基本的な順番になります。

f:id:BegiGrammer:20170603132542p:plain

 fillEllipse(in:)だけでも円は描写できますが、contextの描写の中でaddEllipse(in:)で塗りつぶされていない円を描写する必要があります。そして線の描写と同じようにcloseしてから塗りつぶしの作業をします。

SIMフリーiPhoneの罠

 前置き

 最近の格安SIMの広がりを見ると凄まじいものがあり、多くの人が格安SIMないしはSIMフリースマートフォンに興味を持っているかと思います。日本の携帯事情といえば、Androidのシェアが増えてきたものの以前iOSiPhoneとか)の人気は高いままです。このiPhoneに携帯電話会社の回線の縛りなく格安SIMを入れる場合SIMフリーiPhoneが必要となります。(最近はSIMロックがかかっていてもそのまま使える格安SIMも増えてきました)  しかしSIMフリーiPhoneには思わぬ注意点があるのです。

入手

 さて少し話が逸れますが、まずSIMフリーiPhoneをどのようにして入手するのかを説明していきたいと思います。SIMフリーiPhoneは携帯電話会社のショップには売っていません。主にインターネットか、Apple Storeでの購入となります。

www.apple.com

 もしくはSIMロックのかかっていない海外の携帯会社版のiPhoneを買うこととなります。例えばアメリカのVerizonは4G携帯全てにSIMロックをかけないというポリシーになっているため、アメリカの他の携帯電話会社や日本の携帯電話会社などのSIMを使用することが可能です。このよなものを日本で使用する場合バンド(周波数)をよく確認する必要があります。次の見出しではバンドに関する注意点を米Verizon版iPhone7を例にして書きます。

日本で使える周波数

 まず海外でSIMフリーiPhoneを購入する際の注意点はこちらです。当たり前ですが、日本のApple Store等で買ったSIMフリーiPhoneはこの周波数の問題をクリアしています。

日本版の周波数

f:id:BegiGrammer:20161003125612p:plain

 日本の通信方式のほとんどをカバーする北米版iPhone7を買う際はA1660, A1661となります。米国でCDMAを利用しているのはVerizon, Sprintの二社なのでそちらのiPhoneを買うことになります。ただしSprintは過去に米国内の他のキャリアをロックしたiPhoneを発売したことがあるのでVerizonの方が確実と言えるでしょう。

 もし、A1778, A1784を手にいれて日本で使った場合まずauでは3G回線が使えません。なぜならauはCDMA2000というマイナー方式をとっているからです。(またアクティベートができないようです) docomoではまず800MHz帯の使用ができません。ここはプラチナバンドと呼ばれ、混み合った場所でも通信環境が保証されやすい帯域です。そのため1700MHz帯とバンド1での3G通信となります。(一般的に数字が小さいほど低速ですが、ビルの中や山の上などの劣悪な環境でも繋がりやすいと言われます)Softbankでは日本版と変わらず900MHzから3G使用できます。

 一方でLTEは大体どこも対応しています。

 これらのキャリアは基本的にSIM単体での販売をしていないのでUnlocked iPhone格安SIMで使用することになります。

 例えばyモバイルは3Gに1700MHz, LTEにBand3, 28を使用しているのでA1778等でも問題なく使用できるはずです。

 このようにSIMを売っている携帯電話会社のバンドと対応しているバンドとをよく見て一番適当なものを買うということをオススメします。

アクティベート

 さてSIMフリーiPhoneを買ったからといってすぐさまSIMを挿入しないでください。そもそもSIMフリーiPhoneSIMロックiPhoneの中身は同じであり、アクティベーションサーバーと呼ばれるサーバーでiPhoneの登録(Appleアカウントなどでなくもっと技術的な意味)の際にSIMフリーの証がつけられているかどうかでしかありません。すなわち、アクティベーションサーバーにうまく認識されなければSIMフリーが外れロックがかかることもあり得ます。

 そのようなことがあり得るのでしょうか?

 私は一度経験したことがあります。Verizon版携帯をアメリカで購入し、T-mobileで使用していたSIMフリーiPhoneが、帰国しDocomoのSIMを挿入した際にSIMロックで弾かれたことがありました。すなわち私のそのSIMフリーiPhoneT-mobileSIMロックされていたのです。

 これは特段珍しい話ではなく、インターネットで検索すると幾らかの事例が出てきます。

 「アクティベーションサーバーにうまく認識されない」とはアクティベーションサーバーがメンテナンス中にSIMを挿入し初期起動しアクティベートしたiPhoneはそのSIMでロックがかかるという現象のことです。

 それでは、どのようにしてサーバーの誤認識を防げば良いのでしょうか?アクティベーションサーバーのメンテナンスはアメリカ時間の休日に行われることが多く、平日にSIMの挿入と初期起動(アクティベート)を行うことである程度は防ぐことができます。また、一度SIMを挿入したiPhoneの設定やコンテンツを全て削除しもう一度アクティベーションを行うということはこのようなリスクを伴うのでなるべく控えた方がよいと思います。

(この情報は日本Apple Storeの店員さんから聞いた情報です)

 

SIMロックがかかったら?

 SIMフリーiPhoneにロックがかかった場合どのようにしたら良いのでしょうか?まずApple Japanに連絡しアクティベーションサーバーでの登録の具合を確認してもらいましょう。そして再度SIMフリーにしてもらいます。これが確実にできるのは日本で買ったSIMフリーiPhoneであり、海外版は基本的にその国のAppleの仕事となるので日本のApple Storeではできない可能性があります。

Apple Careの問題

f:id:BegiGrammer:20170520155355j:plain

 これはSIMフリーに限った話ではなく、海外版iPhone全体の問題となります。Apple Careでは画面割れだったら画面の交換修理を、本体にもダメージが及んでいる問題の場合本体の交換を行います。この本体の交換の際に交換できるのは同じ周波数モデルのiPhone同士だけです。iPhone7を例に出すと北米版A1660を交換する場合、日本には同じモデルのがないため同モデルをアメリカから取り寄せとなります。

 また交換品が何かの手違いでSIMロックがかかっているものが送られることがありました。その場合サーバー上でSIMロックを解除する必要がありますが、アメリカ版などの海外版はその申請が何かと面倒で、その海外のがなかなかロック解除に応じてくれない場合あるそうです。

まとめ

 SIMフリーiPhoneを購入する際はなるべく国内版のSIMフリーiPhoneApple Storeで購入することをお勧めします。その場合、SIMを刺す時の日時を少し念頭に置いてアクティベートするとより安全に使用できます。

【Swift】PageBased ApplicationにPage Controlを表示する

導入

 Xcodeにはいくつかの雛形が用意されておりその中にPage-based Applicationがあります。Page-based ApplicationはiOSのホーム画面のように横スクロールでいくつかのページを表示する場合や、Bookアプリのようにめくってページ移動をする場合に使われています。その時に役立つのがPage Controlと呼ばれる「・・・」みたいなドットです。

f:id:BegiGrammer:20170517220206p:plain

 雛形のアイコンにはあたかもPage-based Applicationの代名詞とでもいうかのようにPage Controlのイメージが書いてあるのですが、実際の雛形の中にこれは含まれません。そこで今回はこいつを作ります。

下準備

 作られたばかりのPage-based Applicationは(いかにもデザインセンスの無い色の)めくりカレンダーのようなものになっています。今回はPage Controlの追加なのでこれを横スクロールのiOSのメイン画面のようにします。

 RootViewController.swift、20行目のtransitionStyle.pageCrulから.scrollに変更します。これだけで横スクロールになります。ちなみにその横のnavigationOriantation.horizontalから.verticalに変更すると上下スクロールになります。

f:id:BegiGrammer:20170517225748p:plain

 PageControl追加

 ようやくPage Controlを追加します。現在はRootViewControllerの上にDataViewControllerをaddSubview()している状態なので、またその上にPage Controlを表示します。すなわちRootViewController.swiftでDataViewControllerをaddSubview()した後に新たにPage ControlをaddSubview()します。

 全部載せるほどのものでも無いので変更部分のみ書いてあります。もちろん、pageControlはクラス変数として作っておいてください。

 pageControlを追加するのはRootViewController.swiftの大体30行目、DataViewControllerを追加した後にしてください。Page ControlのデフォルトのpageIndicatorTinColorcurrentPageIndicatorTinColorは透明になっているので、適当な色を指定してください。今回はlightGraydarkGrayを使用しています。func pageViewController()はページをめくる際に呼び出されます。その中で使っているindexOfViewController()ModelControllerクラスの中で定義しています。これに目前(pending)のViewControllerを入れています。同じ関数でページめくりのアニメーションが終わった際に呼び出されるもの(2つめ)の中ではindexの取得がうまくいきません。ページめくりのフェイントに対応するためPageControlの更新はアニメーションが終了した時点で行います。pageControl.currentPageはデフォルトが0で(今回は明示的に0を代入しています)これに現在のindexを代入することで、darkGrayなドットが移動します。

タップでページ移動

 あまり使用している人はいないと思いますが、実はPageControlのドットの右側や左側をタップするとページが進んだり戻ったりします。あまり使われない機能をいちいち書くのが面倒なので、かけたら書きます。そのうち・・・

【Swift3】WKwebViewでWebページのアイコンを自動取得

 作成意図

 Webページにはappleバイス用のアイコンが設定されている場合があり、これが主にブックマークを使用する際のアイコン画像となります。現在このアイコンを取得する機能はWKWebViewに実装されておらず、自力で導入する必要があります。しかし、毎回これを書いていては骨が折れるので、アイコンを取得できるカスタムWKWebViewを作成しました。

ダウンロード

Get url where web page icon. · GitHub

 使い方

 CustomWKWebView.swiftとscript.jsをアプリケーションのディレクトリに置き、xcodeに登録してください。

 CustomWKWebViewDelegateをスーパクラスにしてください。

 webView.getIconImage() を実行すると現在表示中のページのアイコンの取得を試みます。 func urlDidGet(customWebView: , arrURL:) がアイコンの取得時に呼び出されます。以下がサンプルの使い方になります。

 ライセンス

 このカスタムは営利非営利のどちらでも使用可能です。ただし二次配布は許可しません。

問題点

 ATSの設定によりますが、URLSessionのdownloadTaskがブロックされる場合あります。ATSのAllow Arbitrary Loads in Web ContentのYES設定では現在のところWKwebviewしかhttp通信を認められていないので。URLsession用に個別で通信を許可する等の対処が必要になります。

改造等

 現在はapple用にタグが設置されたアイコンとog:imageしか読み込みませんが、icon等の一般的なものも読み込むようにするとより多くの場所でアイコンを取得できます。その場合複数の画像が上がってくることにりますが...

 apple用のwebアイコンを取得する際に複数のアイコンがあり、かつsizeが指定されている場合は最も大きな画像を取得しますが、それでは都合の悪い場合はJavaScriptの方にある判別部分を書き換えてください。(urlDidGet(customeWebView: , arrURL:)で配列が帰って来る理由はswiftの方で判別していた時の名残です) 

【Swift3】TableViewで簡単な設定画面を作る

 iPhoneの純正の設定画面はTableViewを使用して作られています。そしてこれと同じようなものをアプリケーション内でTableViewを駆使して作ることができます。最終的な完成図はこのようになります。

f:id:BegiGrammer:20170323063007p:plain

  空のViewControllerを用意し、TableViewとCellを貼り付けDelegateとDataSourceを設定、cellのidentifierを設定するところの説明は省略します。

f:id:BegiGrammer:20170323063349p:plain

  このようにTableViewのStyleをGroupedにします。するとこのようなStyleになります。

f:id:BegiGrammer:20170323063632p:plain

 コードはこんな感じ。今回はViewControllerを使わずにやっていますが、ViewControllerにTableViewを貼り付ける形でもOK。(StaticなTableViewだとできない) Overrideしなければ普通に使える。

 あとはコードのコメントを参考にして

 

追記 -2018/1/7-

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {

        return 25

    }

でヘッダーとするViewの高さを調整する。

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

        return UIView()

    }

 でString のヘッダーの代わりにUIViewのヘッダーを指定できる

高さを調整しずにViewをヘッダーに指定すると何故か0段目のヘッダーが表示されない。

 

参考というかほどんどパクリ元

www.edumobile.org

【Swift3】WKWebViewの使い方とロード後に呼び出されるメソッド

 iOS8.0からWKWebViewが追加され、現在よりセキュアで安定したWKWebViewの使用をAppleは推奨しています。WKWebViewはStoryBoard上でまだ扱えないのでコードを書いていく必要があります。

WKNavigationDelegateはwebViewが活動中に色々といじれる便利なプロトコルなので一度リリースノートを読んでおくといいでしょう。

WebKit | Apple Developer Documentation

今回はwebページのtitleを獲得するためにページのロード後に呼び出される func webView(WKWebView, didFinish: WKNavigation!) を使用しました。またhttpsとhttpのどちらにも対応する場合 Info.plist -> App Transport Security Settings -> Allow Arbitrary Loads in Web Content を YES にする必要があります。この設定でどちらもセキュアに通信できるのはiOS10以上のデバイスのみです。iOS9や8対応の場合は Allow Arbitrary Loads もYESにします。しかしこれはあまり推奨されない方法です。

2017/03/14現在iOS10のシェアは76%でiOS9のシェアは16%なのでそろそろアプリのサポートを切ってもいい頃合いだとは思います。

App Store - Support - Apple Developer

 webのページを戻したり進めたりする場合昔はScreen Edge Pan Gesture を設置して戻る際の挙動を書かなければいけませんでしたが、今は webView.allowBackForwardNavigationGestures = true にしておくだけで簡単に設定できます。