Personal Factory

Personal Factory

iOSエンジニアの技術ブログ

NumberFormatterで数値を国際化
iOS

NumberFormatterで数値を国際化

個人アプリで風水アプリを作っています。佐藤タケシです。 * 玄空飛星風水 今このアプリの国際化対応をしている最中です。 玄空飛星風水は端末の方位磁石の値を読み取り、風水を判定してくれるアプリです。 こちらのキャプチャのように画面に方位磁石の値を表示しています。 値は小数点第一位まで表示しています。 この値も国際化が必要と気づいたので、そのやり方をご紹介します。 検証環境 * Xcode 14.1 * Swift 5.7.1 * iOS 16.0 * ただし、この記事で紹介するNumberFormatterはiOS 2から利用できるものです。 小数点の国際化 数値に国際化なんて必要なの?と疑問に思った方もいるかと思います。 アラビア数字を使っている限りどの国でも通用するのでは?と思う人もいるでしょう。 今回は小数点に着目しますが、実は小数点に「.(ピリオド)」を表記するのはどの国でも行われているものではありません。 世界を見渡すと、小数点の記号は主に3つの表記があります。 * イギリス式
5 min read
Xcode Cloudを個人開発で利用した感想 2022年11月版
iOS

Xcode Cloudを個人開発で利用した感想 2022年11月版

開発環境 * Xcode 14.1 * macOS Monterey 12.6 はじめに Xcode CloueはAppleが提供するAppleプラットフォームのためのCI/CDサービスです。 * https://developer.apple.com/jp/xcode-cloud/ 去年からBeta版として公開されていましたが、2022年にXcode Cloudがパブリックリリースされました。 CircleCIやBitriseなどすでにCI/CDサービスがたくさんありますが、ついにApple自身がApple開発者のためのCI/CDサービスを提供したということで、個人開発に取り入れてみました。 結果からいうと、とても良かったです。 まだまだリリースしたばかりで、機能は最低限ですが、個人開発では十分です。 逆にチーム開発としては使いづらそうな印象を受けました。 この記事では、私が個人開発で利用した内容を共有したいと思います。 皆さんのXcode Cloud利用の参考になれば幸いです。 あくまで自分の経験や感想を中心に記載するので、Xcode
4 min read
XcodeGenプロジェクトのFirebaseライブラリーをSwift Package Manager経由で追加する
iOS

XcodeGenプロジェクトのFirebaseライブラリーをSwift Package Manager経由で追加する

実行環境 * XcodeGen: 2.32.0 * Xcode 13.4.1 FirebaseをSwift Package Managerで追加したい 個人アプリで、Firebaseを利用しています。 プロジェクトの構成はXcodeGenで生成しており、FirebaseはCocoaPodsで追加させていました。 しかし、Firebase 8.0.0(2021年5月11日リリース)からSwift Package Manager(以下SPMと略します)経由で追加できるようになりました。 * Swift Package Manager for Firebase 私のプロジェクトではFirebaseのインストールがCocoaPodsの唯一の利用目的だったので、SPMに置き換えればCocoaPodsをやめれると考えました。 いろいろ調べて、XcodeGenのproject.ymlの書き方がある程度わかったのでブログに残したいと思います。 利用しているFirebaseのプロダクト 私が利用しているFirebaseのプロダクトは次の2つです。 *
3 min read
イベントレポート

2022 iOSDC Day2感想

Xcode が遅い! とにかく遅い!! 遅い Xcode をなんとかする方法 https://fortee.jp/iosdc-japan-2022/proposal/9d542893-3c30-4077-a85a-1c7ec68caa9c 資料 内容 * XCBBuildSeviceがCPU 900%でとまる * XCBBuildServiceはSPMのバグを踏み反応しなくなる->XcodeはXCBBuildServiceを反応まってXcodeも止まる * 問題のある処理をとめたい * XCBBUILDSERVICE_PATH環境変数を変更 * XCBuildServiceProxyKit * https://github.com/MobileNativeFoundation/XCBBuildServiceProxyKit * SwiftNIOベース * Xcode 14 beta2からこのバグが直ったそう🎉 めでたい * ロック機構の問題 * clang内部のllvmのロック機構でビルド遅くなる *
3 min read
2022 iOSDC Day0感想
イベントレポート

2022 iOSDC Day0感想

iOSDC Japan 2022 今年もやってきました。iOSDC Japan。 https://fortee.jp/iosdc-japan-2022 9/10の前夜祭と9/11のday2に現地で参加してきたので感想を残したいと思います。 ノートアプリのテキストエディタの解体新書 https://fortee.jp/iosdc-japan-2022/proposal/aad51596-674f-4b8a-a24b-868e84453e9a 資料 記事 https://t.co/mof246BqdQ サンプルコード https://github.com/fromkk/TextEditorSample 内容メモ * noteアプリで新しいテキストエディタを実装した際に考えを解説 * 入力した後にスクロール追従 * Drop & Drag * iPadのデザインをreadableContentGuideで良い感じに * 画像の埋め込み * ツールバーはUIToolbarではなく、UIViewで作成。UIScrollViewを入れたか
3 min read
Task.initのクロージャーに[weak self]はいらない。Task.detachedとTaskGroup.addTaskも同様
iOS

Task.initのクロージャーに[weak self]はいらない。Task.detachedとTaskGroup.addTaskも同様

2022年7月29日、インプレスR&D社よりSwift Concurrencyの解説本をリリースしました。 こちらの本は一冊でSwift Concurrencyの機能をほぼ網羅したConcurrency機能の解説本です。 日本語でSwift Concurrencyを学べる解説本はまだ少ないので、Swift 5.5からの非同期処理をうまく書きたい方には必見の本となっています。 さて、せっかくリリースしたばかりなのですが、一部のサンプルコードがあまり良いコードではありませんでした。 すでにサンプルコードのリポジトリは修正済みですが、どのような修正があったのかをこの記事で説明したいと思います。
12 min read
Swift 5.5からのSwift  Concurrencyのasync/awaitの使い方
iOS

Swift 5.5からのSwift Concurrencyのasync/awaitの使い方

Swift 5.5からはSwiftの言語機能としてConcurrencyが登場しました。 これは非同期処理、並行処理のコードを簡潔かつ安全に記述できる機能です。 async/awaitを使えば、同期処理と同じような書き方で非同期処理を記述できます。 またactor型を使えばデータ競合を防ぐことができます。 この記事ではSwift 5.5からのSwift Concurrencyの機能の一つ`async/await`の使い方を解説します。
10 min read
Swift PlaygroundでConcurrencyを使う by Xcode 13.2.1
iOS

Swift PlaygroundでConcurrencyを使う by Xcode 13.2.1

Swift 5.5で登場したSwift Concurrency。 async/awaitを使うことで、並列処理を上から下に流れるように記述することができます。 どんな風に使えるかをSwift Playgroundで試そうとしたところ、Swift Playgroundではいろいろ制限があるようなのでまとめました。 検証環境 * Xcode 13.2.1 * Swift 5.5 _Concurrencyをインポートする Swift Concurrencyの機能をSwift Playgroundで使う場合、まず最初にすることは _Concurrency というフレームワークをインポートすることです。 明示的にインポートしないでConcurrencyの型を実行すると「スコープにそんな型は見つからない」とエラーになります。 手元ではコンパイルエラーにはならず、実行時にエラーが表示されました。 例えば_ConcurrencyをインポートしないでTaskを実行します。 Task.detached {} するとデバックエリアにこのようなエラーが出力されます。 error: reque
2 min read
iOS 15でNavigationBarとTabBarがデフォルトで透過される
iOS

iOS 15でNavigationBarとTabBarがデフォルトで透過される

iOS 15をXcode 13以上で開発していたところ、NavigationBarとTabBarの背景が透過されていることがわかりました。 どうやらXcode 13でビルドをした場合、iOS 15のNavigationBarとTabBarはデフォルトで背景が透過されるようです。 私のアプリでは透過ではなく、iOS 14以前と同じように背景色をつけたかったので、どう修正するのかを調べました。 開発環境 * Xcode 13.2 * iOS 15.2 NavigationBarをiOS 14以前と同じ見た目にする 背景色が透過されるようになった原因 UINavigationBarにはscrollEdgeAppearanceというプロパティがあります。 UINavigationBarAppearanceというNavigationBarの外観設定を司るクラスのインスタンスです。 Navigation ControllerがNavigation BarとScroll Viewを持っている場合で、Scroll Viewのコンテンツの端がNavigation
3 min read
[iOS]枠線の上にViewを乗せようとしたらviewとlayerの重なり順に苦しんだ話

[iOS]枠線の上にViewを乗せようとしたらviewとlayerの重なり順に苦しんだ話

Viewに枠線をつけて、その上にViewを乗せるコードを書いていたらUIViewとCALayerの重なり順に手間取ったのでメモ的に記事にします。 souce code https://gist.github.com/SatoTakeshiX/1b9050a7ea517785e3b45ace0a38a5ac 実行環境 * Xcode 13 * iOS 15.0 * Swift 5.5 (とはいえ、内容はiOS 15でなくても動きます) 枠線の上にViewを表示したい UIViewに枠線をつけて、その上にバッチのようにUIImageViewを乗せようとしました。 ちょうど次の図のようなレイアウトです。 最初の方針として「UIViewのlayerプロパティで枠線をつけて、その上にUIImageViewを表示するAuto Layoutを設定すればよいだろう」と思っていました。 そこでこんなコードを実装しました。 SignboardというViewに緑の枠線を表示するboardViewとその上に王冠のImage ViewであるcrownImageViewを乗せるコードです。
3 min read
VNDetectRectanglesRequestのminimumSizeについて
iOS

VNDetectRectanglesRequestのminimumSizeについて

Visionフレームワークを触っていてわからなかったことがあります。 VNDetectRectanglesRequestのminimumSizeプロパティの意味です。 minimumSizeプロパティは検出する矩形の最小サイズを指定するプロパティです。 分析する画像の矩形が指定したものよりも小さければ、分析処理をしません。 多くの矩形を分析する際は処理を軽くするために指定すると良いものです。 デフォルトが0.2になっており、0.0から1.0の値が指定できます。 let request = VNDetectRectanglesRequest() request.minimumSize = 0.2 ただこの数値の意味がわからないのです。 ドキュメント [https://developer.apple.com/documentation/vision/vndetectrectanglesrequest/2875374-minimumsize] にはこう書かれています。 > The minimum size of a rectangle to detect, as a propor
3 min read
[SwiftUI] GeometryReaderでメソッド/関数を実行したい!
iOS

[SwiftUI] GeometryReaderでメソッド/関数を実行したい!

実行環境 * Xcode 12.5 GeometryReaderでViewのサイズを取得する [SwiftUI] GeometryReaderでViewのサイズを知る [https://blog.personal-factory.com/2019/12/08/how-to-know-coorginate-space-by-geometryreader/] で解説したとおり、SwiftUIでViewのサイズを取得するにはGeometryReaderを使います。 GeometryReaderのハンドラーから渡されるGeometryProxyのインスタンスでViewのサイズがわかります。 struct LocalVariableView: View { var body: some View { GeometryReader { proxy in Text("\(proxy.frame(in: .local).debugDescription)") } } } struct LocalVariableView_
2 min read
[SwiftUI] PreviewProviderで実行されているかを確認

[SwiftUI] PreviewProviderで実行されているかを確認

確認環境 * Xcode 12.5 * iOS 14.5 SwiftUIでPreviewされているかをプログラムで確認する方法 PreviewでViewを表示している場合、環境変数のXCODE_RUNNING_FOR_PREVIEWSの値が"1"になっています。 なので、次のように場合分けをするとプログラム上Previewで表示されているかを判別できます。 var body: some View { if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" { Text("running on preview") } else { Text("running on not preview") } } 実行するとキャンバス上でこのようなViewが表示されます。 シミュレーターではこうです。 うまく切り分けられましたね。 参考 ios - How do you check
1 min read
[2021年版]XcodegenでCarthageとCocoapodsを使う最小プロジェクトを作成
iOS

[2021年版]XcodegenでCarthageとCocoapodsを使う最小プロジェクトを作成

個人アプリのプロジェクト構成をXcodegenで作り直そうかと思っています。 個人アプリはライブラリーの依存関係をCarthageとCocoapodsを使って管理していますが、Xcodegenではどういう記述でproject.ymlを書けばいいのかが検討つきませんでした。 理解を深めるために最小プロジェクトを作ることにしました。 この記事ではXcodegenでCarthageとCocoapodsを使う最小プロジェクトを解説します。 実行環境 * Xcode 12.4 * Xcodegen * Carthage: 0.37.0 * Cocoapods: ディレクトリ 今回はTryXcodegen という名前のプロジェクトを作成して、CarthageとCocoapodsでライブラリーを管理し、プロジェクト生成にXcodegenを利用します。 最終的なディレクトリ構造は次のとおりです。 主要なもののみ掲載しています。 $ tree -L 2 . ├── Cartfile ├── Cartfile.resolved ├── Carthage │ ├── Build ├
3 min read
CarthageのXcode 12エラー: This usually indicates that project itself failed to compile.を直す
iOS

CarthageのXcode 12エラー: This usually indicates that project itself failed to compile.を直す

Xcode 12でCarthageでライブラリーをビルドしようとしたら、ビルドが失敗して以下のようなエラーを出力されました。 Carthageのバージョンは0.36.0で試しています。 This usually indicates that project itself failed to compile. Please check the xcodebuild log for more details: /var/folders/jm/pyy6p95j177_btm91tj0mkdm0000gn/T/carthage-xcodebuild.WPi9jL.log > このエラーは下記issuesから引用 https://github.com/Carthage/Carthage/issues/3019 実行環境 * Xcode 12.4 * Carthage: 0.36.0 -> 0.
2 min read
Clubhouseのスーパー楕円をSwiftUIで作る
iOS

Clubhouseのスーパー楕円をSwiftUIで作る

近年流行りだした音声SNS, Clubhouse [https://www.joinclubhouse.com/]。 デザインの特徴の1つにふわっとした丸みを帯びた楕円のアイコンがあります。 これは「スーパー楕円」と言われているそうです。 丸よりも丸みを感じる!? スーパー楕円の魅力とデザイン | Spinners Inc. [https://www.spinners.work/posts/kudakurage-superellipse-desgin/] この楕円を@tokorom [https://twitter.com/tokorom]さんがUIKitで実装してました。 スーパー楕円UIをiOS+Swiftで実装する | Spinners Inc. [https://spinners.work/posts/swift-superellipse/] この記事を読んでSwiftUIでも作りたくなったので、作ってみます。 実行環境 * Xcode 12.2 * iOS 14.2 実装方針 tokoromさんと同じようにもと記事 [https://www.spinner
4 min read
SwiftUIで開閉式メニューの作り方
iOS

SwiftUIで開閉式メニューの作り方

SwiftUIで下からニュッと表示する開閉式メニューの作り方を解説します。 > この記事は私が2020年12月22日に発表した資料、 「SwiftUIで作る開閉式メニュー [https://speakerdeck.com/satotakeshi/swiftuidezuo-rukai-bi-shi-meniyu] 」を記事化したものです。 動作環境 この記事は以下の環境で動作を確認しています。 * Xcode 12.2 * iOS 14.2 開閉式メニューを作ろう 今回作る開閉式メニューの動きをgifでみてみましょう。 親Viewを作る まずは親Viewを作りましょう。 struct ContentView: View { @State var isShowMenu = false var body: some View { ZStack { Button(action: { withAnimation { isShowMenu.toggl
4 min read
SwiftUIのデータ管理 Property Wrapper編

SwiftUIのデータ管理 Property Wrapper編

SwiftUIでアプリを開発していると@Stateや@Bindingの使い分けについて迷ったりしていませんか? SwiftUIではデータを管理するProperty Wrapperがたくさんあります。 @State、@Binding、@StateObject、@ObservedObjectなどなどです。 Property Wrapperそれぞれの特徴を理解できれば、SwiftUIのアプリ開発がはかどるでしょう。 今回はSwiftUIのデータ管理を行うProperty Wrapperの使い分けについて解説します。 > この記事は私が12月9日に発表した資料、 「SwiftUIのデータ管理 [https://speakerdeck.com/satotakeshi/swiftuifalsetetaguan-li] 」を記事化したものです。 SwiftUIのデータ管理記事一覧 * SwiftUIのデータ管理 Single Source of Truth編 [https://blog.personal-factory.com/2021/01/20/whats-the-single
7 min read
SwiftUIのデータ管理 Single Source of Truth編
iOS

SwiftUIのデータ管理 Single Source of Truth編

SwiftUIでアプリを開発していると@Stateや@Bindingの使い分けについて迷ったりしていませんか? SwiftUIではデータを管理するProperty Wrapperがたくさんあります。 @State、@Binding、@StateObject、@ObservedObjectなどなどです。 Property Wrapperそれぞれの特徴を理解できれば、SwiftUIのアプリ開発がはかどるでしょう。 今回はSwiftUIのデータ管理に欠かせないSingle Source of Truthという考え方について解説します。
3 min read
UITableViewをコードで実装する最速の方法
iOS

UITableViewをコードで実装する最速の方法

UITableViewでリスト表示を実装するさい、よくやるやり方は、StoryboardやXibファイルでCellを作って、そのidentifierをView Controllerで指定する方法です。 ですが、UITableViewCell標準の表示で十分な場合にファイルが分かれるのは面倒です。 なんとかコードで済ます方法がないかと探したらありましたのでご紹介します。
2 min read
[iOS 14]WidgetでDeep Link作成
iOS

[iOS 14]WidgetでDeep Link作成

iOS 14からWidgetという機能が登場しました。これはアプリを起動しなくてもHome画面にアプリ情報をユーザーに届けられる機能です。 今回はWidgetをタップした時に特定のアプリ画面が開けるようにする、Deep Linkの作成方法について解説します。 検証環境 * Xcode 12.2 * iOS 14.2 WidgetとDeep Link Widgetをタップすると何も実装しなければ、本体アプリが起動されます。 しかし、Widgetに表示されているコンテンツと関連した画面に遷移できればユーザー体験が向上します。 そのためにはWidgetにDeep Linkを作る必要があります。 Widgetのサイズとリンクの数について まず最初にWidgetのサイズとリンクの数についてお話します。 開発者が作れるWidgetの大きさはSmall, Medium, largeの3つです。 実はWidgetはサイズによっておけるリンクの数が決まっています。 Smallサイズはひとつだけで、MediumサイズとLargeサイズは複数置くことができます。 例えば、Appleの
3 min read
[iOS 14] Widgetでカウントダウン
iOS

[iOS 14] Widgetでカウントダウン

WidgetのViewを更新するにはTimelineProviderプロトコルのgetTimelineメソッドを実装してタイムラインという何時何分にどんなデータでViewを更新するのかをあらかじめWidgetKitに伝える必要があります。 Todoアプリなどでイベントをカウントダウン表示したい場合を想定します。 毎秒更新するようにタイムラインを作成すればうまくいくかと思いきや、各アプリによってWidgetを更新できる回数は決まっています。 TimelineProviderのドキュメントにはこう書かれています。 > Each configured widget receives a limited number of refreshes every day. Several factors affect how many refreshes a widget receives, such as whether the containing app is running in the foreground or background, how frequently the widge
2 min read