ビギグラマーのノート

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

【Swift 4】NSAttributedString ⇆ HTML の変換とUITextViewへの表示

 やりたいこと

 NSAttributedStringとUITextViewを使えばリッチなテキスト表現ができることはご存知かと思います。今回、なんらかのデータファイルからUITextViewへ表示し編集、それを保存する必要があったのでどうにかしようと思ったのです。

How to do

HTML → NSAttributedString

        let html = "<html>ほにゃらら〜</html>"

        

        let encoded = html.data(using: String.Encoding.utf8)!

        let attributedOptions : [NSAttributedString.DocumentReadingOptionKey : Any] = [

            .documentType : NSAttributedString.DocumentType.html,

        ]

        let attributedTxt = try! NSAttributedString(data: encoded, options: attributedOptions, documentAttributes: nil)

        textView.attributedText = attributedTxt

 tryを使っているので実装ではdo-catchが必須になります。

f:id:BegiGrammer:20180315033947p:plain

NSAttributedString → HTML

        let attT = textView.attributedText!

        let documentAttributes = [NSAttributedString.DocumentAttributeKey.documentType: NSAttributedString.DocumentType.html]

        let htmlData = try! attT.data(from: NSRange(location: 0, length: attT.length), documentAttributes: documentAttributes)

        let html = String(data: htmlData, encoding: .utf8)

        print(html ?? "Empty")

結果

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<meta http-equiv="Content-Style-Type" content="text/css">

<title></title>

<meta name="Generator" content="Cocoa HTML Writer">

<style type="text/css">

p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 25.0px '.SF UI Display'; color: #e60012}

p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px '.SF UI Text'}

p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 10.0px '.SF UI Text'; color: #009944}

span.s1 {font-family: '.SFUIDisplay'; font-weight: normal; font-style: normal; font-size: 25.00pt}

span.s2 {font-family: '.SFUIText'; font-weight: normal; font-style: normal; font-size: 12.00pt}

span.s3 {font-family: '.SFUIText'; font-weight: normal; font-style: normal; font-size: 10.00pt}

</style>

</head>

<body>

<p class="p1"><span class="s1">Tomato</span></p>

<p class="p2"><span class="s2">English</span></p>

<p class="p3"><span class="s3">Royal blueberry blue and white.<span class="Apple-converted-space"> </span></span></p>

</body>

</html>

ご丁寧に全文描いてくれいています。

愚痴

 File → NSAttributedString → UITextView(編集) → なんらかのData → File

 こういうことをやりたいが為にこの一週間XMLでフォントスタイルを定義しそれを解読する奴を必死に作っていましたが、ひょんなことでこのような楽な方法を見つけてしまいました。わだじの いっじゅうかん かえじで!

参考

stackoverflow.com

stackoverflow.com

【Xcode 9.2】PlaygroundでLibraryを使う

 Playground Single View使ってますか?

 最近(それほど最近でもないけど)XcodeのPlaygroundにSingle Viewモードが追加されました。

f:id:BegiGrammer:20180104103033p:plain

いちいちテストアプリを作ってやっていくのはめんどくさいので非常に重宝していますが、Cocoapodで入れられるLibraryを使えないことが大きな欠点です。この記事ではそのSingleViewモードでLibraryを使えるようにします。

How to

 まずはPlaygroundのSingle View単体で作ります。

f:id:BegiGrammer:20180104103436p:plain

 次にCocoapodをインストールしたXcode Projectを作ります。これに必要なライブラリをよしなにインストールしておいてください。

 作成したおいたPlaygroundをXcode Projectにドラッグ&ドロップします。

f:id:BegiGrammer:20180104104548p:plain

 追加されるさいのオプションを聞かれるので、Add to targetしCopy item if neededにチェックを入れておきます。

f:id:BegiGrammer:20180104104758p:plain

 Playground追加後ビルドします。 これでプロジェクトに追加したPlaygroundの中で必要なライブラリがImportできるようになりましった。

f:id:BegiGrammer:20180104105748p:plain

Playgroundでライブラリを使うために色々とサイトを巡ったのですが、結局このような非常に簡単な方法にたどり着きました。全体的に見直して見ると、Workspaceに別に作っておいたD&DでPlaygroundを追加するだけでした。

お疲れ様でした

問題点

  • ソフトウェアキーボードが隠れて見えること
  • TextFeild等にMacのキーボード操作が効かないこと
  • アニメーションがラグいこと 
  • self.view.centerが使えないこと  (viewWillAppear内で使用可能)
  • たまにxcodeが落ちること (index out of rangeすると落ちる?)

追記

 しばらくデザイン関係のチェックのために使用していましたが、TableViewでミスるとXcodeが落ちたりして結構使いずらいことがわかりました。しかし、単純なTextLabelを作ってみたり、Libraryでデータを弄ってみたりすることに関しては非常に使いやすかったです。当方の環境がMacBook Pro Mid 2015 i7 2.2GHz iGPUなのでdGPUを搭載したものやiMacだとスムーズに作業ができるかもしれません。

参考

m.pardel.net

qiita.com

【Java】EventListenerで他クラスにイベントのタイミングを伝える

 前置き

 諸事情でAndoroidではないデスクトップアプリでJavaを使用することになりました。私はSwiftしかりオブジェクト指向の言語で毎回クラス間、特に子→親の間のイベント通知に戸惑うようで今回も例に漏れず半日ほど唸っていました。

 SwiftではNotificationで比較的自由かつ簡単にクラス感のイベント送受信ができたのですが、JavaではEventListenerを作成することで大体同じような感じになりました。

 同じようにメソッドの呼び出しとしてsuperクラスによるものもありますが、これは単にメソッドを借りて実行しているため今回の用途ではうまく動きませんでした。

本文

 口で言うよりまずコードを見てもらった方が早いですね。

 

 今回は親となるReciveEvent.javaインスタンスにしてあるEventBeginning.javaからのイベントを受け取ると言うことをします。EventBeginning.javaeventListenerを実行するとのそのイベントが親のbuttonAction()を発火させると言うことです。

 この独自のEventListenerの構成を設定しているのがListenerInterfaceでこれに発火させるものを追加していくことができます。又、引数をEventListenerを指定すれば値を渡すこともできます。

【JavaScript】Switchに複数の評価する値を入れる

 やりたい事

 ここでやりたいことはJavaScriptのSwitch文に複数の評価する値を入れて判別するということです。文章にするより実際のコードを見てもらった方が良いかもしれません。(もちろんこのコードは正常に動きません。swiftのコードです。)

 この場合defaultが選択されるのを期待しますが、 実際動かしてみるとpoint1が選択されます。

なのでこうします。

 これの味噌はtoString()で配列をStringに直す事です。そうでないと比較はアドレスの違いを見ることになり期待した動きをしません。数値以外にもtoString()でStringにして比較をしても良いものは大抵この方法でできます。しかしHTMLの要素などのtoString()しても一定の値しか返ってこない場合は使用できません。もっと要素を展開して識別できる値を見つける必要があります。

 結局のところ文字列と数値がくらいが安全に比較できる限界でしょうか。また、これは値を文字に直して完全一致の場合、すなわち両方の評価する値が一致する場合のみcaseが実行されるのでどちらか片方が一致する場合という条件をつけることができません。

【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を刺す時の日時を少し念頭に置いてアクティベートするとより安全に使用できます。