BambooHero

#Programming #iOS #Investment #LifeHacks

iOS Development

iOSアプリバージョンを取得するユーティリティ

バージョン取得ユーティリティの実装例 フレームワークでユニットテストを実行すると意図しない結果になる 任意のバンドルを指定できるように改良する バージョン取得ユーティリティの実装例 iOSアプリの現在のバージョンを取得するコードは以下のように実装…

LLDB's po command not work on Xcode13 M1 Mac. How to fix it?

LLDB's po command is the essential tool when writing UI tests. However, I got some errors when using po command on Xcode13 on M1 Mac. (lldb) po app error: Couldn't realize type of app Or, I got nothing. (lldb) po app t = 425.92s Requesting…

[SwiftUI] PreferenceKeyの基本的な仕組みを知る

子ビューから親ビューにデータを渡す仕組みとして頻繁に使用するPreferenceKeyですが、 reduce()メソッドの実装ってこれで合ってるんだっけ? onPreferenceChangeにはどういう値が入ってくる? といった点について、毎回デバッグして調べてたので、改めて整…

[Swift]一度だけ変更可能なプロパティを実装する方法

初期値はnilで、その後1回値を代入したら、その後何度代入しても値が変わらないプロパティを実装したい。 didSetを使うと、以下のようにシンプルに実装できました。 struct User { var id: Int? { didSet { if oldValue != nil { id = oldValue } } } } var …

[SwiftUI] Listでifを使うと初回ロードが重くなる...?

Listを使って縦スクロール型のビューを組んでいて、初回表示が重くなる問題にぶち当たっています。 実際のコードはもっと複雑ですが、やりたいことはこんな感じです。 List内の各行はItem.typeごとに別々のビューを表示させるようにしています。 struct Cont…

GeometryReader自体の高さを子ビューのフレームサイズと同じにする

記事タイトルをどうすべきか結構悩んだんですがw、要はやりたいのはこういうことです。 Rectangleの高さを、与えられたフレーム幅を基に動的に変化させたいとします。 ここではフレーム幅の半分のサイズの高さを指定することとします。 struct ContentView:…

[SwiftUI] インラインでTextにImageを埋め込むデザインを実装しようとして苦労した話

テキストの先頭にアイコンがあり、2行目のテキストの先頭をアイコンの下に潜り込ませるデザインを、あなたはどのように実装しますか? SwiftUIのTextを使うと、テキストに画像をインラインで埋め込むことができるので、以下のように簡単に実装できます。 Tex…

iOSシミュレーターのフォルダをサクッと開くスクリプト

以下のスクリプトを実行すると、現在実行中のシミュレーターのフォルダを開くことができます。 バンドルの中身を確認したり、ドキュメントフォルダにファイルが保存されていることを確認したりしたいときに、このスクリプトがあるとさくっとシミュレーターの…

[SwiftUI] カスタムビューに独自のModifierを実装する方法

アプリの複数の画面で汎用的に使えるカスタムビューを作ったが、画面によって一部分だけ色を変えたいという要件が出てきたら、どう実装すれば良いでしょうか? 例えば、ユーザ情報を表示する汎用的なビューを以下のように実装したとします(テキスト思いっき…

肥大化したUITextViewをテスタブルで再利用可能な構造にリファクタする

複雑なテキスト処理ロジックを持つテキストエディタを実装しようとすると、UITextViewのカスタムクラスが肥大化することはありませんか? 例えば、ユーザがテキストを入力すると、その内容を検証したり、ハイライトしたり、その他様々な処理を行うという要件…

XcodeGenを導入するにあたりお世話になった記事3選

XcodeGenを導入するぞ!といっても、最初は何から手を付けていいのかわからない人が多いのではないでしょうか? 私も最初はそんな状態でしたが、先人の皆さまが素晴らしい記事を残してくれていたので、年季の入った大規模なプロジェクトにもかかわらずXcodeG…

Bitriseのビルド環境に事前にインストールされているものが何かを知る方法

Bitriseのビルド環境(Stackと呼ぶ)では、HomebrewやCocoaPods、Bundlerなど、iOSアプリをビルドするために必要なツールが事前にインストールされています。 ただ、これらのツールのバージョンがいくつなのか、他にどんなツールがインストールされているか…

BitriseでGemをキャッシュする方法

BitriseのCache:Pushステップを利用して、Gemをキャッシュさせます。 なお、Bitriseのキャッシュの仕組みについてはこちらの記事で紹介しているので参考にしてください。 bamboo-hero.com Gemをキャッシュさせる方法 こんな構成のワークフローを作成します。…

Knuffを使ってプッシュ通知のテストをする

これまでPusherというツールを使ってプッシュ通知受信のテストをしてたのですが、最近久しぶりに使ってみたらエラーが出てしまいプッシュ通知が送信できなくなっていました。 github.com ↓プッシュ通知を送信している様子。 Unable to read: Read connection…

[Swift] structのMemberwise Initializerを残しつつカスタムのInitializerも実装する方法

Swiftの構造体(struct)はInitializerを一つも実装しない場合にMemberwise Initializerと呼ばれるInitializerが自動で生成されます。 Structure types automatically receive a memberwise initializer if they don’t define any of their own custom initi…

ScrollView内のビューが画面上に表示されたことを検知する仕組みを実装する

ScrollView内のビューが画面上に表示されたらなにか処理をするという仕組みを実装したので、実装方法をご紹介します。 実装したもの コードの解説 ビューが画面に表示されたかどうかを判定するための情報を整理する 各情報を取得する ビューが画面に表示され…

[SwiftUI] .alert()の記述箇所を気をつけないと子ビューのアラートが表示されなくなる

親ビューと子ビューそれぞれでアラートを表示する実装がある場合、.alert() Modifierの記述箇所を気をつけないと、子ビューのアラートが表示されなくなります。 正しく表示されるケースの実装はこちらです。 struct ParentView: View { @State var showAlert…

Swiftで[String: Any]型の等価性チェックをする

Swiftで以下のコードはコンパイルエラーになります。 Any型がEquatableに準拠していないというのが理由です。 let dict1: [String: Any] = ["foo": "bar"] let dict2: [String: Any] = ["foo": "bar"] print(dict1 == dict2) // Protocol 'Any' as a type ca…

The Composable Architecture(TCA)で再利用可能なコンポーネントを作る方法

TCAのサンプルの中に Reusable Favoriting Componentというものがあります。 「何かをFavoritingする」という機能を提供する、汎用的なコンポーネントの実装例です。 Getting Startedのサンプルと比べて若干ReducerやStateの書き方が違うので混乱するんです…

Swiftのプロトコルやジェネリクスを駆使して汎用性の高いAPIクライアントを実装する

正直いまだにジェネリクス周りがそんなに得意じゃないのですが、色々苦戦しながらも割と汎用的で使いやすいAPIクライアントをジェネリクスを使って実装することができた気がするので、それについてご紹介したいと思います。 「プロトコルやジェネリクスを駆…

SwiftのComputed PropertiesはFunction内でも宣言できる

今まで知らなくて発見だったのでメモ。 SwiftのComputed PropertiesはFunction内でも宣言できます。 struct State { var foo = "foo" } var state = State() func testComputedProp() { var result: Bool { // ここにComputed Propertiesが宣言できる! some…

UIViewRepresentableなビューにTCAを組み込むべきか?

まだSwiftUIにはUITextView相当のものが用意されていないので、UIViewRepresentableを使ってUITextViewをSwiftUIビューで使用できるようにしています。 さらに、自分が関わっているプロジェクトではThe Composable Architecture(TCA)を採用しているのです…

slatherでiOSアプリのカバレッジを可視化する

Xcodeだけでもカバレッジの数値を見ることはできますが、特定のディレクトリやファイルをカバレッジ対象から除外するなどといった細かいことはできません。 最近業務でiOSアプリのリアーキテクチャを進めているのですが、旧アーキテクチャではテストを全く書…

MintでインストールしたパッケージをBitriseにキャッシュさせる方法

iOSのプロジェクトにSwiftLintを導入していて、SwiftLint自体はMintでインストールしています。 Bitrise上でSwiftLintを実行するためにはビルド前にSwiftLintをインストールしておく必要があるため、Xcode Test for iOSステップの前にScriptステップを配置し…

APIKitのエラーハンドリングを整理する

APIKitではどのようなエラーが定義されていて、それらがどういうときにスローされるかを整理します。 APIKitでAPIClientを実装するときに、エラーハンドリング周りをどう実装するかを考える際の参考になるかと思います。 前提とサンプルコード SessionTaskEr…

isMovingToParentとisMovingFromParent

UIViewControllerのisMovingToParentとisMovingFromParentがどのようなときにtrue or falseになるかがわからなかったので調べてみました。 それぞれの定義 検証してみた まとめ 検証コード それぞれの定義 isMovingToParent A Boolean value indicating whet…

The Composable Architecture(TCA)でアクションシート(Action Sheet)を実装する方法

The Composable Architecture(TCA)のサンプルからアクションシート(Action Sheet)の実装方法について学びます。 今回扱うサンプルはこちらです。 01-GettingStarted-AlertsAndActionSheets 「Action sheet」ボタンをタップするとアクションシートが表示…

The Composable Architecture(TCA)で複数画面で状態を共有する方法

複数画面間での状態の共有をどのように実装するかは、iOSアプリ開発において一つの大きな議論のテーマではないでしょうか? TCAは複数画面間での状態の共有という課題に対してどのようなソリューションを提供するのか、サンプルから学んでいきましょう。 01-…

The Composable Architecture(TCA)でアラート(Alert)を実装する方法

The Composable Architecture(TCA)のサンプルからアラート(Alert)の実装方法について学びます。 今回扱うサンプルはこちらです。 01-GettingStarted-AlertsAndActionSheets 「Alert」ボタンをタップするとアラートが表示され、アラートの中の「Increment…

【UIKit版】The Composable Architecture(TCA)で画面遷移を実装する方法

前回TCAで画面遷移を実装する方法について学びましたが、UIKit版の同様のサンプルも提供されているので、今回はこちらを説明したいと思います。 SwiftUI版との違いに注目して説明するので、是非以下の記事と照らし合わせて見てください。 bamboo-hero.com 対…