文字っぽいの。

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

自動で泡のハンドソープが出てくるやつを買った。

これを買った。今までは手動でハンドソープを出していたけども、毎日何度もプッシュするのが面倒だったので購入。

この商品を選んだ理由としては、

  • 充電式
    • 乾電池入れ替えるの面倒なので
    • バッテリーがへたる頃には本体自体がへたって買い替えだろうなと思ってる
  • 出てくる泡の量が調整できる
    • 「全然少ない」とかなりそうなので、調整できるのが良かった
  • ボトル容量が大きい
    • 詰め替えは面倒なので大量に入れておきたい
  • 詰替しやすい
    • ボトルを外して取って流し込むだけなので簡単
    • 口も広いので良い
  • ホワイトでシンプルな形でシルバーが入っていない
    • キラキラかっこいいって要素は不要なので

やっぱり、自動で丁度いい量のハンドソープが出てくるのは便利。

Amazonレビュー見てると数ヶ月で壊れたってのがチラホラあるので、どうなるかなと思いながら使っていきます。

複数のライブラリを含むPackageをSwiftPMで利用する方法。

環境

  • Xcode 13.2.1
  • Swift 5.5.2

やりたいこと

The Composable ArchitectureFirebase iOS SDK のように、XcodeのPackage Dependencies経由で入れるとこんな感じで複数のライブラリが内包されていて、使いたいものを選択して利用するタイプのライブラリ。

f:id:FromAtom:20220104201200p:plain

これを Package.swift でも選択して利用したい。

やりかた

たとえば、The Composable ArchitectureのComposableArchitectureだけを利用したい場合は、こうやって Package.swift に書けば良い。

import PackageDescription

let package = Package(
    name: "SamplePackage",
    platforms: [.iOS(.v13)],
    products: [
        .library(
            name: "SamplePackage",
            targets: ["SamplePackage"]),
    ],
    dependencies: [
        .package(name: "swift-composable-architecture", url: "https://github.com/pointfreeco/swift-composable-architecture", .upToNextMajor(from: "0.32.0"))
    ],
    targets: [
        .target(
            name: "SamplePackage",
            dependencies: [
                .product(name: "ComposableArchitecture", package: "swift-composable-architecture", condition: .when(platforms: [.iOS]))
            ])
    ]
)

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杯分ぐらい作れて良い。

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