文字っぽいの。

文字を書いています。写真も混ざります。

SwiftでLatoフォントを簡単に使えるLatoSwiftをつくりました。

f:id:FromAtom:20220104023507p:plain

作ったもの

github.com

できること

UIKitやSwiftUI製のアプリで、簡単にLatoフォントを扱えるようになります。SwiftUIでも使えるので、macOS向けにSwiftUIアプリを作った場合でも利用可能です。

for UIKit

import LatoSwift

let latoRegularFont = Lato.uiFont(ofSize: 16)
let latoBoldFont = Lato.uiFont(ofSize: 16, weight: .bold)
let latoLightItalicFont = Lato.uiFont(ofSize: 16, weight: .light, style: .italic)

for SwiftUI

import SwiftUI
import LatoSwift

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Lato Regular")
                .font(Lato.font(ofSize: 16))
            Text("Lato Bold")
                .font(Lato.font(ofSize: 16, weight: .bold))
            Text("Lato Light Italic")
                .font(Lato.font(ofSize: 16, weight: .light, style: .italic))
        }
    }
}

こんな感じで簡単にLato指定で表示できます。

f:id:FromAtom:20220104024448p:plain

フォント(.ttf)も一緒に入ってくるので、使うときはこのライブラリを導入するだけで済みます。

なお、現時点では自分しか使わなさそうなのでSwiftPMのみの対応です。

注意点

READMEにも書いてありますが、LicensePlistでライセンス表記を自動生成している場合、LatoSwiftのライセンス(MIT)は読み込まれますが、Latoフォント自体のライセンス(SIL Open Font License)を読み込んでくれません。license_plist.yml を自分で用意して、ライセンス表記を追加してあげて下さい。

地味に面倒なので自動で読み取らせたいのですが、どうにもやり方が分からなくて断念しました。誰か詳しい人がいたら教えて下さい。1

モチベーション

副業や個人アプリでLatoフォントを使うことがままあるのですが、毎回Fontファイルをダウンロードして、読み込み用のコードやそれっぽい仕組みを用意するのが面倒だったので作りました。

また、SwiftPM中心のプロジェクト構成にしていると、Asset周りで地味に面倒な感じになったので「これならライブラリ化しちまえ」となったわけです。

fromatom.hatenablog.com


  1. LICENSEファイルに2つ分のライセンスを書いてしまえば良さそうだけど、それでいいのかよく分かっていない。

SwiftPMでAssetsを含んだtargetを別のtargetで呼んでSwiftUI Previewするとクラッシュする。

わけわからんタイトルだけど、そのままなので仕方ない。

環境

  • Xcode: 13.2.1
  • Swift: 5.5.2

背景

iOSDC 2021でこの発表をみて、SwiftPM中心のプロジェクト構成にしようとする人は多いだろう。

fortee.jp

自分もその一人で、その中ではまった問題。

SwiftPM中心のプロジェクト構成にするとMulti Module化がしやすくなるので、機能ごとや画面ごと(プロジェクトの設計によるが)にModule(Package.swiftでいうTargets)を分割していく。

そうすると自然と .xcassets も分割されていく。上記発表ではBundleに Bundle.module を指定しましょうという話がされていて、基本的にはそれでうまくいく。しかし、SwiftUIのPreviewを使おうとすると特定条件でPreviewができなくなる。

条件とエラー

下記のコードをまとめたリポジトリはこちら

github.com

こういう Package.swift 構成になっている。

let package = Package(
    name: "ImageAssetPackageSample",
    platforms: [.iOS(.v15)],
    products: [
        .library(
            name: "ImageAssetPackageSample",
            targets: ["ImageAssetPackageSample"]),
    ],
    dependencies: [
    ],
    targets: [
        .target(
            name: "ImageAssetPackageSample",
            dependencies: ["ImageAsset"]),
        .target(
            name: "ImageAsset",
            dependencies: [])
    ]
)

この中で、ImageAssetが.xcassetsを持っていて、

public struct ImageAsset {
    public static let blueSquare: UIImage = UIImage(named: "BlueSquare", in: Bundle.module, compatibleWith: nil)!
}

というコードで画像が得られるようになっている。ここで、ImageAssetPackageSample というTargetでSwiftUIのViewを作ってPreviewをすると

unable to find bundle named ImageAssetPackageSample_ImageAsset

----------------------------------------

CrashReportError: XCPreviewAgent crashed

(中略)

ImageAsset/resource_bundle_accessor.swift:27: Fatal error: unable to find bundle named ImageAssetPackageSample_ImageAsset

(後略)

というエラーでクラッシュしてPreviewができない。一方でImageAssetを依存に含んだImageAssetPackageSample を利用して、Project側のアプリコードでSwiftUI Previewを利用すると普通に表示できる。

つまり、

  • .xcassets を含んだTargetを別のTargetで利用してPreviewする:NG
  • .xcassets を含んだTargetをProject内のコードでPreviewする:OK

となっている。

原因

SwiftUI Previewer crashes while in swift package that depends on another's packages Bundle.module reference - Using Swift - Swift Forums

Bundle.module がPackageのPreview時には生成されずにNot foundでクラッシュするらしい。

対策

ワークアラウンドなコードを書く

このエラーで調べると出てくるけど、自分でBundle.moduleに相当するものを書いてあげれば動く。

public let imageBundle = Bundle.myModule
private class CurrentBundleFinder {}
extension Foundation.Bundle {
    static var myModule: Bundle = {
        /* The name of your local package, prepended by "LocalPackages_" for iOS and "PackageName_" for macOS. You may have same PackageName and TargetName*/
        let bundleNameIOS = "LocalPackages_TargetName"
        let bundleNameMacOs = "PackageName_TargetName"
        let candidates = [
            /* Bundle should be present here when the package is linked into an App. */
            Bundle.main.resourceURL,
            /* Bundle should be present here when the package is linked into a framework. */
            Bundle(for: CurrentBundleFinder.self).resourceURL,
            /* For command-line tools. */
            Bundle.main.bundleURL,
            /* Bundle should be present here when running previews from a different package (this is the path to "…/Debug-iphonesimulator/"). */
            Bundle(for: CurrentBundleFinder.self).resourceURL?.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent(),
            Bundle(for: CurrentBundleFinder.self).resourceURL?.deletingLastPathComponent().deletingLastPathComponent(),
        ]
        
        for candidate in candidates {
            let bundlePathiOS = candidate?.appendingPathComponent(bundleNameIOS + ".bundle")
            let bundlePathMacOS = candidate?.appendingPathComponent(bundleNameMacOs + ".bundle")
            if let bundle = bundlePathiOS.flatMap(Bundle.init(url:)) {
                return bundle
            } else if let bundle = bundlePathMacOS.flatMap(Bundle.init(url:)) {
                return bundle
            }
        }
        fatalError("unable to find bundle")
    }()
}

Providing XCAssets Folder in Swift… | Apple Developer Forums

ただし、Multi Module化して、細かく画面を分けてTargetが分割されると、無限にこのコードを書いていく事になって不毛感がすごい。

ミニアプリを作る

Target内でPreviewせずに、Project側で参照してPreviewすることはできるので、Module毎にPreview用のミニアプリを作っていく。SwiftPM中心のプロジェクト構成にしていれば、Projectを増やすことが容易なのでわりと許容できる対応な気もするが、コードを書いている場所とPreviewする場所が別になるので地味に不便。

SwiftUI Previewを使わない

諦めて全部ビルドしてシミュレーターで確認してしまう。ミニアプリと大体同じ解決方法。

Asset系を1つのTarget(Module)にまとめてしまう

筋が悪い感はすごいが、ワークアラウンドをTarget毎に書かなくても良くなる。ただし、どのAssetがどのTargetで利用されているか分からなくなるので、将来的に負債になることが明白。あまり取りたくない選択肢。

FontやColorだけならまだいいかなぁ……という感覚。

まとめ

実は別の解決方法があるかもしれないので、知っている人がいたら教えてほしい。できれば、Xcode側で解決してほしいなー。

2021年買ってよかったもの。

良くて使い続けてるものだけ書いていく。

LGの有機ELテレビ

だいたい下記の記事に書いたとおり。ソフトウェアが良くできているので、使っていて不快感が少ない。もちろん発色は最高。

fromatom.hatenablog.com

新しいWindows PC

ハチャメチャに古いPCを使い続けてきたけど、一念発起して購入した。 「今買ったらグラボとか在庫復活したら損では?」って思っていたけど、その後もずっと在庫は破滅していた。その間にゲームできたのでOK。RTX3080なので、だいたいなんでも快適に動いて便利。

fromatom.hatenablog.com

おふろ整理グッズ

山崎実業を信じろ。

fromatom.hatenablog.com

Anker Soundcoreの防水スピーカー

お風呂に入るときに使ってる。 ラジオ系とか耳だけで情報が得られるタイプのYouTubeとかPodcastを流している。 お風呂、とにかく暇なのに作業工数が無駄に多いので、音声メディアがあると助かる。

充電がMicroBなのがちょっとだるい。

Blue Microphones Yeticaster ストリーミングセット

マイクとマイクスタンドのセット。正直このマイクスタンドが欲しくて買った。普通のマイクスタンドの鉄骨クレーンみたいなのがダサいし使いにくくて嫌いだったので、これに変えられてよかった。使用感も思っていたとおりかなりいい。

山崎実業 ダンボール収納

山崎実業しか勝たん。Amazon楽天を多用していると床に積まれていくダンボール。これは、畳んで立てて収納できるもの。地味だけど床にダンボールがあるよりストレスが減るのが良い。

自作パームレスト

作ってよかった。ただ、やっぱ手汗によってガサついてきたので、耐水性ニスとか塗ったほうがいいかもしれない。

fromatom.hatenablog.com

鏡のくもり止め

便利。曇らないというのは便利。

はがせる両面テープみたいなやつ

Ankerのスマホ充電器が微妙に移動して不便なので、これで固定した。机の上で動いてほしくないものを固定するのに非常に便利。

食洗機「ラクア」

タンクにも分岐水栓にも対応している食器洗い乾燥機。前まで使っていた食洗機が壊れてしまったので買い替え。「パナソニックから薄型の出たじゃん」と思うかもしれないが、あれは確かに奥行きは薄いが地味にでかい。今回は分岐水栓対応なので、自分で分岐水栓を買って工事して取り付けた。

食洗機、「洗濯機があるのって便利だよね。」と同じ程度にあって当然のレベルになっているので、まぁそら便利だよねって感じ。

縦型・乾燥機能付・洗剤自動投入付の洗濯機

縦型でも乾燥はちゃんとしてくれる。とはいえ我が家は急ぎじゃない限り干すのでそっちのメリットより、自動投入のメリットがかなり大きかった。 あと洗濯機は容量がデカければデカいほど強い。

fromatom.hatenablog.com

GoPro HERO 10

サバゲーの様子を撮影して、編集して楽しんでいる。内部のチップが更新されてサクサク動くのでとてもいい。

バンカーリング

地味便利。

fromatom.hatenablog.com

Ankerが似た商品を出したので、そちらでもいいかも。

発泡スチロールカッター

家電系を買うたびに発泡スチロールが届き、手で割っていると破片で部屋が破滅するので購入した。 時間的には腕力のほうが早いけど、部屋が汚れずに発泡スチロールが細かく切れるのが良い。

こんな感じ。来年も色々買っていきましょう。

「駄目な隣人」の新宿店に行ってきた。

f:id:FromAtom:20211204160351j:plain

新宿周辺で時間を潰す必要があり、せっかくなので今年の7月にオープンした駄目な隣人に行ってきた。

キャッシュレスのお店で食券をキャッシュレスで買うことになる。店員に声をかけると現金でも払えるらしい。

机の上には生卵、のり、鰹粉、胡椒、ニラがあって食べ放題。

f:id:FromAtom:20211204160823j:plain

一人ずつ席が簡易にセパレートされていて、これらのトッピングも一人ずつに用意されてる。よくラーメン屋に行くとセパレートの向こう側に欲しい調味料があって困ることがあるけど、これならそれがないので良い。

生卵は(良識の範囲で)使い放題なので、ラーメンに入れたり卵かけご飯にしたりできる。卵かけご飯にしたいなら、ライスも注文しておこう。

f:id:FromAtom:20211204161047j:plain

野菜で取られたスープであっさりしていて美味しかった。

あんまりお酒を飲まなくなった。

お酒をあまり飲まなくなった。といっても禁酒をしているわけじゃないし、禁酒する気もない。飲み会には行きたいし、餃子を作ったら「これはビールや」とビールを飲む。

前までは毎日ビール2缶とか飲んでいたけれど、なんとなく「お茶で良いな」となってからお茶を飲むようになったらお茶になった。ビールはうまいが酔うと疲れる問題があり、その点お茶だと旨いし疲れない。

最初は紅茶、緑茶、烏龍茶を飲んでいたけれど、寝る前にカフェインガブガブ飲んだら流石に睡眠の質が下がりそうなので、万能茶を飲んでいる。

これがノンカフェインでなかなか美味しいし、結構長く味が出る。1パックでサーモスのでかいタンブラー2杯分ぐらい作れて良い。

ちなみに「お酒を飲まなくなったら目覚めがスッキリするように」とか「身体が軽くなった」とかそういうことはまったく無い。ビールの缶を洗ったり捨てる手間が減ったのが一番のメリットだと思う。

Amazonブラックフライデーで買ったもの。

今年もブラックフライデーですね。例年、サイバーマンデーのほうが安くなっていて悲しみを得たりしますが、安くならないかもしれないので買うしか無いという戦いを強いられています。

下記ではブラックフライデーセールで購入したものをまとめていますが、セールで安くなっていないものも買っています。普通に必要だからついでに買ったやつです。あしからず。

TV周り

PS5を楽しむために、4K120fpsな有機ELテレビを買った。 - 文字っぽいの。

でも書いたけど、TVを買い替えた。

そして、TV用に分波器を買った。

アンテナ線は壁からnasneに来て、nasneからこのケーブルで分波させてTVにつながっている。nasne経由での接続方法については、公式PDFが分かりやすくてよかった。

作業部屋の有線LAN整備

我が家のモデム・ルーターはリビングにあり、作業部屋から離れていて廊下を経由しないと届かない。隣の部屋ならばLANケーブルを引っ張っていくのを気軽にできたけど、地味に距離があったので今まで諦めていた。

今回、ブラックフライデーに併せてこの作業頑張ることにした。Cat7警察の方々はおとなしくしていて下さい。

壁に添わせてひたすらニンジャピンで止めていった。天井にLANケーブルを貼り付ける作業がひたすら面倒だったけど、ちゃんと速度アップしたので満足。

デスクトップPC周りの改善

デスクトップPCを床に直置きしていて、掃除やらケーブルの取り回しやらが大変だったので、それを改善するために購入。

有線LAN整備で増えたスイッチングハブだったり、キーボードだったりをここにまとめていく。

家事関係

家電を買うと発泡スチロールで梱包されているけど、それをカッターで切ったり、腕力で割るとめちゃくちゃ大変なので購入。100円ショップでも売っていたけど、線が短すぎて役に立たなかったので、コンセント式の大きめのを買った。

ディスプレイの掃除用に購入。キムワイプならティッシュと違ってホコリが出ないので便利。

食洗機用洗剤。安いうちに買いだめ。

ちなみにジェルタブはこういう容器に詰め替えると、取り出しやすいし蓋を締めるのも楽なので便利。

机周り

スタンディングデスクごっこをするために、折りたたみ机を購入。

高さ調整ができるので買ってみたけど、好みの高さになってくれるかはまだ届いていないので不明。折りたたみもできるので、使わないときは片付けられる。ベッドやソファーで作業するときにも便利そうなので買ってみた。

PS5を楽しむために、4K120fpsな有機ELテレビを買った。

ようやくPS5を手に入れたので、PS5のスペックを最大限に活かせるテレビを買った。Amazonブラックフライデーセールで安くなっていたのも決め手の一つ。

色々と調べていたけども、

というスペックを満たすのは今現在だとこれしか選択肢がなさそう。

このシリーズで一番小さい48インチで、これで十分というか、かなり大きい。ギリギリテレビ台に乗っかってセーフな大きさだった。

使ってみての感想

マジックリモコンが便利

リモコンは無線式で赤外線じゃない。LGのマジックリモコンは昔から色んな人が便利だと言っている。これはリモコンをテレビに向けて上下左右に降ると、テレビ内のカーソルが一緒に動いてくれるやつ。普通のテレビだとボタンを無限にカチカチしないといけないけど、これなら動かすだけでいいので楽ちん。

こんな感じで操作できる。

www.youtube.com

画質

そらもうきれい。発色もいいし楽しい。

音質

案外いい。自分はBOSEサウンドバーを利用しているので普段はそちらから音を出しているけど、最初にセットアップをして、あれこれ起動したり再生したりしてみた感じ、十分に使える音質で再生できている。もちろん音質にこだわりがある人だったり、低音が響いてほしい人だと不満は感じると思うが、テレビとしては十分な音質で鳴っている。

光沢なので反射する

結構反射するので、アニメとかゲームとかしていて暗い画面になると自分の顔がこんにちはする。アンチグレアフィルムを買うことも考えたけど、このデカさをいい感じに貼れる気が全くしないので諦めてる。黒い画面でキモいおっさんが映るバグ、PSP時代から直っていなくて困る。

値段

10万円は高いけど、4K 120fpsのディスプレイを探すと液晶でも同じような値段帯になる。2020年モデルで型落ち品にはなるけれど、初期の値段が20万かつブラックフライデーセールで2万円弱安くなっているのを考慮すれば、妥当な値段だと感じている。

ゲーム

肝心のゲームだけど、そもそも120fpsに対応しているゲームが少ないので、先行投資という感じがある。フォートナイトが対応していたのでやってみたけども、そこまで目をみはる変化はない印象。たぶんこれはフォートナイトを普段からやってないからだと思う。だんだんと対応しているゲームが増えてくるだろうし、のんびり待っていればよさそう。

ちなみにBloodborneをやってみたら30fpsしかサポートしていないらしく、残像がすごくてやる気が消え去った。