Developmentここで言うSingletonというのは、ある種のグローバル変数を指している。そもそもクライアントアプリケーションの開発においては、実質的なグローバル変数が出現しやすい。環境にたった一つしか存在しない、存在すべきでない、というものが見出せる。タイムゾーンがそれである。アプリケーション内のタイムゾーンはシステムに合わせるのが自然であり、アプリケーション中で複数存在することはほとんど起こり得ない。frameworkのTimeZoneである。システムのタイムゾーンはTimeZone.currentで取得できる。これはSingletonパターンのインターフェースに近い(本当にインスタンスが一つであるかどうかをここでは問題にしない)。このように環境中で存在する個数が限定されるような値を表すのに、Singletonパターンが用いられることがある。Singletonパターンを用いると、単体テストを書くのに不便だったり、あるいは多用することでコードベースのメンテナンス性が低下するなどとして、嫌われることも多い。このような問題は、DIのようなアプローチを用いることで軽減できるだろう。SwiftUIのEnvironmentSwiftUIでは、タイムゾーンの取得に@Environmentを使う。以下のようにしてTimeZoneのインスタンスを得られる。wrapperを使い、EnvironmentValuesのpropertyをKeyPathとして(\.timeZoneのように)与えると、環境の値を読み取ることができる。Environmentの上書き環境の値は上書きすることもできる。modifierを呼び出すと、そのviewの子孫の環境を上書きできる。"GMT")!)全てを上書きできるわけではなく、EnvironmentValuesのpropertyにsetが設定されているものだけを上書きできる。タイムゾーンを上書きするのはあまり有意義とは言えないが、例えばEnvironmentValues.isEnabledを上書きするのは理解しやすいユースケースである。特定のview以下を全てdisabledにするのは、リーズナブルだ。false)のショートハンドであろう。新しいEnvironmentを作るEnvironmentValuesを拡張してpropertyを追加することで、独自の値をEnvironmentに持たせることができる。propertyは追加できないが、幸いなことにEnvironmentValuesはEnvironmentValues.subscript(_:)によってストレージを提供してくれる。macOSで、viewが所属するNSWindowを環境から取得できるようにしてみる。(Singletonの例にはならないが......。}}このようにEnvironmentKeyに準拠した型を作って、EnvironmentValuesを拡張する。以下のように、NSHostingViewを初期化するときにNSWindowへの参照を与える。windowとして、NSWindowにアクセスできる。EnvironmentとDIコンテナこうしてみると、EnvironmentはViewをターゲットとしたDIコンテナのような役割を果たしている。これはObservableObjectを対象としたEnvironmentObjectでも同じだが、Environmentの場合はObservableObject以外もその対象になる。Environmentは、ViewModifierからも参照できる。EnvironmentalModifierがそれだ。EnvironmentalModifierは、それ自体がViewModifierでありながら、resolve(in:)メソッドを実装することで、EnvironmentValuesの値を元にして別のViewModifierを解決することができる。EnvironmentはViewModifierに対しても依存を提供できる。DIコンテナとしては万能ではないが、これまでSingletonパターンを使っていたようなものの置き換えとしては十分だろう。EnvironmentとContextReactに親しんでいれば、EnvironmentはReactのContextとほとんど同じということに気づくだろう。Reactでは内部的にContextを使って実現されるようなライブラリと似たようなことが、Environmentでも実現できそうだ。まとめSwiftUIのEnvironmentを説明して、独自に拡張する方法を紹介した。DIコンテナとの類似性から、Singletonパターンの置き換えとしての可能性を示した。SwiftUIは昨秋にリリースされたばかりで、不完全な印象を抱きがちではあるが、Environmentのような仕組みがしっかりと整備されており、高いポテンシャルを持っているように思う。id:yigarashi(ワイイガラシ)がいる。似ているが、あるとき一緒に仕事をすることになって、紛らわしさが限界を超えた。yashiganiyigarashiそうとわかって見たら、なるほど「y」で始まって「i」で終わるのが似ているね、くらいに思うかもしれない。不意にSlackやGitHubで見かけると、一瞬どちらかわからない。この紛らわしさをより俯瞰してみるため、画像にしてみました。Photoshopで作ったどうだ紛らわしいだろう。全体的な形がなんだか似ている。ところでこの画像はPhotoshopで作った。テキストにガウシアンぼかしをかけて、その後から二値化した。かっこいいから、もっといろいろ試してみたい。するのを、macOSやiOSの仕組みでやってみるのが、本題である。Textでテキストの画像を作るまずはテキストを画像化しないと始まらない。Graphics)で素朴に実装できる。TextのAPIを使ってCGImageを作る。このときpaddingを設定できるようにすると、あとで都合がいい。Imageを使うことを検討する。以前CoreImage.CIFilterBuiltinsで試したように、CIFilter.gaussianBlur()を使えば、ガウシアンぼかしは簡単だ。あとは二値化するだけだが、ここで手が止まる。意外なことに、組み込みのフィルターには二値化が存在しない。Languageによるカスタムカーネル二値化は簡単そうなので手作りする。Languageで書く。ThresholdBinary.metalを以下の内容で作った。Settingsに追加したMTLLINKER_FLAGSキーに-cikernelを、それぞれ設定する必要がある。}}RGB値から輝度成分を取り出すために、YUV色空間のYを計算する。これが閾値を超えていれば1、そうでなければ0とすることで、二値化できる。このカーネルは以下のように読み込める。二値化のカーネルが書けたので、あとは実際に画像を加工するだけだ。cgImage}CIImage.clampedToExtent()を使うのがコツで、ガウシアンぼかしをかけるときに画像の端が変な色になってしまうのを防げる。iOSでもmacOSでも同じように動くはずだ。なんだかちょっとかっこよくないですか。参考文献Metalは初めて使うので、ちょっとだけ勉強しました。Swiftオフィシャル感のあるSwiftのformatter/linterであるところの、swift-formatを試した。SwiftのGoogleフォークで生まれたものがベースになっているようだ。5.1に対応するswift-5.1-branchブランチがあり、後者を試している。インストールHomebrewでインストールしたかったのでFormulaを用意した。https://gist.githubusercontent.com/cockscomb/183acd19d2f5e127045dc43c6c472535/raw/63c935672b4e8c9d6f2056785283a6d6b7d31b77/swift-format.rbビルドに2分くらいかかった。(もしかするとMintというのを使うといいのかもしれないが、試していない。filenamesdump-configurationswift-formatの設定は、JSONで表現される。デフォルトの設定は以下のようにdumpできる。1}Documentation/Configuration.mdというドキュメントがある。デフォルトでインデントがスペース2つだった。Guideに倣っているためである。buildersのようなDSL的なユースケースが増えてきたときに、インデントが深くなりやすいから、スペース2つの方がいいというトレンドになるかもしれない。一般的なスペース4つに変えた。.けっこういろいろ出てくる。.swift-formatは、ファイル名が.swift-formatの場合には省略できる。trueしておくといい。)こうすると、出力がXcodeの求める形式と合っているので、エディタにwarningが表示される。closureを許さないルールに引っかかる。可読性が落ちるので妥当なルールとも思うが、SwiftUIのTutorialをみると、Buttonで使っているパターンである。actionのクロージャをメソッドとして切り出すのが正攻法だろうが、無効にしてもいいだろう。NeverUseImplicitlyUnwrappedOptionalsというのでも引っかかる。String!のようなのは、あまり行儀がいいとはいえないものの、Xcodeのテンプレートでも使われるパターンである。部分的にswift-formatのルールを無効にできるといいのだが。部分的なlintの無効化masterにはDocumentation/IgnoringSource.mdというのがあった。以下のようなコメントを書くことで、コメントが書かれた次の行からASTで1ノード分、swift-formatが無視してくれるというものらしい。5.1ではまだ使えなさそうだった。formatswift-formatなので、もちろんformatできる。.Makefileも用意しておく。.おもしろいところでは、ネームスペース代わりのinitを潰したstructをenumに書き換えてくれた。フォーマットの感じは悪くなく、(プロジェクトが小さいためか)パフォーマンスも特に気にならない。手元でちょっと使うのには適しているだろう。CIで動かそうとするともうちょっと準備が必要で、競合するSwiftLintの方がノウハウが蓄積されていて便利かもしれない。そのうち安定版がリリースされて、Swiftのツールチェーンにバンドルされたり、Xcodeとのインテグレーションが整備されたりすると、さらに使い勝手がよくなりそう。file]が、ファイル名が.swift-formatの場合に省略できる旨を追加し、全体的に省略するようにした。09:27apple/swift-formatを試すTweetもっと読むコメントを書く2019-11-06息子にカメラを与える日記まだ2歳半で早すぎると思うけど、普段から僕のカメラを羨ましがっているので、少しくらい乱雑に扱われても大丈夫そうなカメラを買った。W150というのにした。耐衝撃性能を宣伝しているくらいなので、きっと頑丈なつくりになっている。ブルーが子供らしくてかわいいかと思ったが、息子は「白がいい」というので、ホワイトにした。子供は子供らしいものを欲しがらない。W100が発売されている。W150ということのようだ。子供にも扱いやすいインターフェースを備えている。光学3倍ズームとかフラッシュとかも付いているけど、今のところそんなに活用していない。フラッシュは、誤って子供が有効にしないか気がかりである。上面にストラップ取り付け部が2つ付いているのはポイントが高い。ネックストラップは付属しないので別に買った。子供はカメラを落としたり、その辺に置いてきたりしがちなので、ネックストラップがあるとよいが、長さの調節幅が大きいものを選ばないといけない。別売のソフトケースも買った。カメラを構える息子ということで妻が入院している最中にカメラを買って、一週間と少し経った。息子はどこへ行くにもカメラを首から下げて、たまに思い出したら写真を撮る。大人の真似をして妹である赤ちゃんの写真を撮っているときは感慨深かった。いえちゃんとした写真が撮れるのはまだ稀だ。息子自身はそんなことお構いなしで、自分用のカメラを喜び、写真を撮る行為そのものを楽しんでいる。おもちゃみたいなものだけど、そのうち真価に気付くことを期待している。小さい子供にカメラを持たせると困ることもある。カメラに夢中になって注意散漫になるので、道を歩くときに危ない。ストラップを持ってカメラを振り回すことがある。撮っていいとか悪いとかの区別がない。家の中とか明らかに安全な場所以外では、親がちゃんと見ていられる時にだけカメラを持たせるようにしないといけない。IIIへの関心が下がって、寿命が伸びた。IIIもおすすめです。frameworkを使うのが簡単だ。画像をハードウェアの支援で高速に処理でき、内蔵された様々なフィルターを使うこともできる。10.4で初めて搭載されて以来、しっかりとアップデートされ続けている。Imageの色々なフィルターをSwiftから扱いやすくなった。Codingを活用したAPIだった。frameworkは、GUIでユーザーに操作させることを想定しており、文字列などから動的に扱えるように作られている。(あるいは組み込みではないフィルターがインストールされている場合もあり、いずれにしてもKVCは有用である。)反面で、フィルター名やフィルターとパラメータの対応に気を配る必要がある。8のタイミングで、KVCではないAPIも整備され、CIFilter.init(name:parameters:)やCIImage.outputImageを使って、以下のように書けるようになった。fatalError()}さらにこれのショートカットで、CIImage.applyingFilter(_:parameters:)メソッドを使い、以下のようにも書ける。見た目はかなりよくなったが、ガウシアンぼかしのために"CIGaussianBlur"フィルターを使って、パラメータとしてkCIInputRadiusKeyを与える、ということは知らなければならない。10の頃にはCIImage.applyingGaussianBlur(sigma:)メソッドなどが追加され、いくつかの基本的なフィルターが容易に利用可能になった。10.15から、新たにCIFilterにたくさんのクラスメソッドが追加された。このうちCIFilter.gaussianBlur()を使えば、これまでと同じ処理を以下のように書ける。CIGaussianBlurになっているので、型を利用して簡単に扱えるようになっている。このようなクラスメソッドが、組み込みのフィルターそれぞれに用意されている。CoreImage.CIFIlterBuiltinsを忘れやすいので注意が必要だ。Imageのmodulemapをみると、以下のようになっている。ImageのAPIは徐々に改良が加えられている。ユースケースに応じて異なるAPIを使うのがよいだろう。単純にガウシアンぼかしを掛けたいのであれば、CIImage.applyingGaussianBlur(sigma:)が最も簡単である。いったショートカットが用意されていない組み込みのフィルターを利用するなら、CIFilterBuiltinsがよい。組み込みではないフィルターを利用するような場合は、必然的にCIImage.applyingFilter(_:parameters:)メソッドやKVCを使うことになる。09:37CoreImage.CIFilterBuiltinsTweetもっと読むコメントを書く2019-10-27二人目の子供が生まれました日記およそ一週間前の21日午前1時頃、僕と妻の二人目の子供が生まれました。予定日を10日も過ぎて生まれた息子とは違い、予定日翌日のことでした。3,200グラムの女の子です。日が変わる頃に病院へ行って、そこからあっという間に産まれました。息子のときより小さいせいか、なんだか違った風に感じています。その息子もまた新たな家族の誕生を喜んでおり、赤ちゃんの顔を覗き込んだり、なんだかんだと話しかけたりしています。二人目ということで、僕にも妻にもいくらか心の余裕がありましたが、一方で前回とは違って2歳半になった息子もいるので、心配もしました。実際にこの一週間は僕と息子の二人で生活していましたが、息子の成長に驚かされるばかりでした。この二人暮らしのことは、僕にとっても生涯の思い出になりそうです。この誕生に伴って、僕も少しの間だけ育児休業させていただくことにしました。仕事をしていない自分への恐れもありますが、しっかり子育てにコミットして、これまでと違った自分を見つけたいとも思っています。引き続きよろしくお願いいたします。Chromeのフォントの表示が変わる、ということがあった。ProN」を指定していても、この指定が効かずにフォールバックされてしまうというものである。Sans(ヒラギノ角ゴシック)」だけになったのが原因とされている。trackerにissueが登録されている。APIの呼び出し方によっても結果が異なるようだ。ProN」が見つかる。2]]}NSFontManager.availableMembers(ofFontFamily:)でフォントが見つかるのは、Appleが互換性を保とうとしたからだろう。NSFontManager::availableFontsForFamilyの該当部分をみると、NSFontManager.availableMembers(ofFontFamily:)を呼び出すようになった。insensitiveにフォントを見つけてくれるようだ。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。