SwiftUI+Golang+Heroku Postgresで遊んでみた感想と知見

技術iOSSwiftUIGolangPostgreSQLHeroku

はじめに

あけましておめでとうございます。今年もよろしくお願いいたします。

本年度一発目の記事は、技術のインプットアウトプット通じての備忘録シリーズです。

作ったもの

今回サンプルとしてつくったものは単語帳アプリです。 ざっと機能としては

  • ユーザーが設定したカテゴリを選択
  • 選択後カテゴリに該当する単語が出現、答えを任意のタイミングで見ることができる

のシンプルな感じで 1 日で開発が終わるようなレベルに設定しました。ちなみにユーザーは自分しかいない前提で進めています

採用技術

技術は以下の通りです。採用理由は自分が使いたかったから!!(結局興味があったりモチベが出るものが一番いいのよ個人開発は)

  • Client (app): SwiftUI+Combine
  • Server: Golang(フレームワーク: gin)
  • DB: Heroku Postgres

バックエンド側は Heroku フル活用で事足りるはずなので使わせてもらって、アプリ側は久々 SwiftUI で書きました

得た知見(ハマったところ多め)

Client, Server, DB, Heroku 周りで詰まったところをまとめます。これは余談ですが、Go で作ったアプリケーションを Heroku で扱う公式チュートリアルが優秀すぎて、想像以上にスムーズにできたのでよかったです

SwiftUI で元の画面に戻る処理

UIKit でいうdismiss(animated:)を SwiftUI でやるにはPresentationMode構造体にアクセスして、dismiss()を呼んであげます

// 遷移元のView

// presentationModeの環境変数を取得
@Environment(\.presentationMode) var presentationMode

// 元画面に戻る処理
presentationMode.wrappedValue.dismiss()

iOS15 以降なら、環境変数presentationModeでなくdismissにアクセスすればすんなりできそうです(参考)

NavigationLink で遷移した画面の上に謎のスペースができる際の対処法

UI を調整している時に、なぜか上側に謎のスペースができていたのでnavigationBarTitleDisplayMode.inlineに指定して解決(参考)

HogeView {
    // SwiftUI.View
}
.navigationBarTitleDisplayMode(.inline)

特定の処理が終わったタイミングで NavigationLink を使って画面遷移したい

API との通信処理が終わったあとに画面遷移をしたいときは、NavigationLinkisActiveフラグを通信が終わった時にtrueに変えてあげることで実現できます。(参考)

NavigationLink(destination: QuizView(words: viewModel.words), isActive: $shouldShowQuizView) {
    Button(action: {
        viewModel.fetchWords(
            by: selectedCategoryId,
            success: {
                // success callbackのときにshouldShowQuizViewをtrueにする
                self.shouldShowQuizView = true
            },
            failure: {
                print("Failed to fetch data from api")
            }
        )
    }) {
        Text("START")
    }
}

Heroku デプロイでapp not compatible with buildpack (Go 編)

以下コマンドで go のバージョンとモジュールの依存関係を記したgo.modを作成し、デプロイしてあげて解決。(参考)

go mod init {GIT_REPOSITORY_URL}

Heroku デプロイで cannot execute binary file: Exec format error

ローカルでコンパイルの際に OS とアーキテクチャ の指定をしてあげてクロスコンパイル、その後バイナリをデプロイすることで解決(参考 1, 2)

## fish
env GOOS=linux GOARCH=amd64 go build -o bin/terminology-memo-api -v .

Heroku デプロイでapp[web.1]: bash: bin/: No such file or directory

Procfileでバイナリの存在するパスを記して解決

web: bin/{BINARY_NAME}

参考: 上述の公式チュートリアル

Go で作ったアプリケーションでno required module provides package

下記コマンドを実行して依存しているモジュールを更新(参考)

go mod tidy

改行コードを PostgreSQL で扱う

E を追加したい文字列の先頭にいれてあげて解決(参考)

INSERT INTO words (name) VALUES (E'明日\n晴れるかな')

updated_atを自動的に更新してくれる制約を追加

MySQL ならon update current_timestampを DDL に追加してあげるだけで OK だが、PostgreSQL だと同等の機能がないので、トリガーを描いてあげる必要がある。。。ので、このサイトを参考に書かせていただきました

最後に

やる気が出た時にガツッとやる開発は久々だったが、楽しいしまた違う学びがある。