<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>2024/12 on Fumiya Tanaka | Emitter Follower</title>
    <link>https://blog.fummicc1.dev/posts/2024/12/</link>
    <description>Recent content in 2024/12 on Fumiya Tanaka | Emitter Follower</description>
    <generator>Hugo -- 0.118.2</generator>
    <language>ja-jp</language>
    <lastBuildDate>Mon, 23 Dec 2024 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://blog.fummicc1.dev/posts/2024/12/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>SwiftのObjectIdentifierを勉強する</title>
      <link>https://blog.fummicc1.dev/posts/2024/12/23/</link>
      <pubDate>Mon, 23 Dec 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.fummicc1.dev/posts/2024/12/23/</guid>
      <description>はじめに この記事はSwiftのObjectIdentifierについての記事です
ObjectIdentifierとは ObjectIdentifierとはクラスまたはメタタイプの一意のidを表す型です。 structやenum, 関数、タプルに対してはObjectIdentifierを生成できなく、classやactorに対してObjectIdentifierを生成できます。
// --- Structに対してはObjectIdentifierを生成できない --- struct S {} let s = S() let num: Int = 0 ObjectIdentifier(s) // Error: Argument type &amp;#39;S&amp;#39; expected to be an instance of a class or class-constrained type ObjectIdentifier(num) // Error: Argument type &amp;#39;Int&amp;#39; expected to be an instance of a class or class-constrained type // --- Classに対してはObjectIdentifierを生成できる --- class B { var value: Int init(value: Int) { self.value = value } } actor A {} let b = B(value: 0) let a = A() ObjectIdentifier(b) ObjectIdentifier(a) structに対してObjectIdentifierを生成しようとするとエラーになる ObjectIdentifierによる比較は参照が同じという意味になるので===と同じ意味になる認識です。</description>
    </item>
    <item>
      <title>GeoHashを可視化できるアプリを作ってみた</title>
      <link>https://blog.fummicc1.dev/posts/2024/12/19/</link>
      <pubDate>Thu, 19 Dec 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.fummicc1.dev/posts/2024/12/19/</guid>
      <description>はじめに こんにちは、Swift Advent Calendar 2024の19日目を担当しますfummicc1です。 この記事では、ジオハッシュ（GeoHash）を可視化できるアプリについての話を書きました。 Swift Advent CalendarなのでSwiftに関連する話も書いたつもりですが、Swift以外の話も含まれているのであらかじめご了承いただけると嬉しいです。
この記事に書いてあること ジオハッシュについて ジオハッシュを可視化するアプリを作った話 ジオハッシュを確認できるアプリを作った際のSwiftに関連する話 ジオハッシュとは ジオハッシュは地図上の特定の区域を表現した文字列のことやそのアルゴリズムのことを指します。世界地図に対して「経度を2分割→緯度を2分割」という処理を繰り返すことで生成されるビット列をハッシュ化することで文字列を生成します。
ジオハッシュの例: 区域ごとに一意の文字列が割り当てられる ジオハッシュの生成では、境界を区切って0,1を割り当てる作業を緯度・経度ごとに行います。経度だけに絞ってみると下記のように分割されていきます。
経度を1bitで分割 経度を2bitで分割 経度を3bitで分割 どこまで分割を行うかでビット列の長さが変わり、長ければ長いほど狭い区域を表現するジオハッシュ文字列となります。
ジオハッシュのビット列は、経度と緯度それぞれについてのビット列を交互に並べたものです。
例えば、経度のビット列が「11100」で,緯度のビット列が「10001」の場合、ジオハッシュは「1110100001」となります。
ビット列は5bitごとに32種類の英数字にマッピングされます。数字10個 + アルファベット22個からa,i,l,oを除いたものの合計32種類から構成されます。
ジオハッシュ生成の流れ このジオハッシュから、地点の緯度・経度の区域を特定することができます。
例えば、日本はおおよそ1桁のジオハッシュでは「w」もしくは「x」で表現されます。ジオハッシュの桁が長ければ長いほど、その文字列が示す区域が狭くなるので1桁のジオハッシュだと結構な領域を示しています。詳しい制度についてはこちらに記述がありました。
日本はおおよそwかxに属する 西日本付近でxからwに変わる ジオハッシュの特性を応用することで、「ある地点の近くにある場所」の探索を文字列の比較で実現ができることができます。(ただし、多少の精度の誤差があることに注意が必要です。)
ジオハッシュをSwiftで実装したい 勉強も兼ねてGeoHashSwiftというリポジトリに実装しました。ですが、既にGeoHashというSwiftで実装されたライブラリがあったのでそちらも参考に実装をしました。
ジオハッシュを可視化するアプリが欲しかった ジオハッシュのライブラリを作った後に実装が正しいことを確認する必要があったのですが、文字列を見ても正しいジオハッシュかどうかが直感的に分からなかったので入力した緯度経度から生成されるジオハッシュを簡単に確認できるアプリを作りました。
検索機能もつけてみました。（手元で動かすととても重いです）
ビット列の長さをスライダーで変えられることができて、マップの中心のジオハッシュと周囲の区域のジオハッシュが表示されるアプリとなっています。
周囲のジオハッシュは幅優先探索で5ステップ先の周囲までを取得しています。全てのジオハッシュを取得すると2 ** ビット列の長さのジオハッシュを取得することになるので、計算が重くなったので断念しました。
5ステップ先のジオハッシュを取得するだけでも、Map上で動作確認をすると処理が重いと感じたので改善に取り組んだことをメモします。
Viewに記述された処理をメインスレッド外で実行する SwiftUIのViewはMainActorであるため、Viewに直接計算メソッドを書いている場合、処理がメインスレッド上で実行されてしまいます。今回はGlobalActorを定義してメソッドをactorで隔離させることでメインスレッドで処理が走らないようにしました。
@globalActor struct ComputationActor { actor ActorType {} static let shared = ActorType() } struct ContentData: Identifiable { var bound: [CLLocationCoordinate2D] = [] var geohash: GeoHash var id: GeoHash { geohash } } struct ContentView: View { // .</description>
    </item>
    <item>
      <title>SwiftUIのEmptyViewのonAppearは呼ばれることがある</title>
      <link>https://blog.fummicc1.dev/posts/2024/12/16/</link>
      <pubDate>Mon, 16 Dec 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.fummicc1.dev/posts/2024/12/16/</guid>
      <description>SwiftUIのEmptyViewはレイアウトに影響しないことで知られています。 EmptyViewはViewが存在しないことを意味するのでonAppearメソッドも呼ばれないと想定されます。 ただ、RootViewにEmptyViewのみを配置した場合はonAppearメソッドは呼ばれるので注意が必要です。
@main struct SampleApp: App { var body: some Scene { WindowGroup { ContentView() // ContentViewだけを表示するとonAppearは呼ばれる // ContentView2() // ContentView2だけを表示するとonAppearは呼ばれない } } } struct ContentView: View { var body: some View { EmptyView() .onAppear { print(&amp;#34;onAppear is called&amp;#34;) } } } struct ContentView2: View { var body: some View { EmptyView() EmptyView() .onAppear { print(&amp;#34;onAppear is not called&amp;#34;) } } } ContentViewではView HierarchyにEmptyViewがあって、ContentView2ではView HierarchyにEmptyViewがないのでonAppearは呼ばれないみたいです。
ContentView ContentView2 onAppear is called onAppear is not called おわりに 簡潔な記事ですが、EmptyViewのonAppearはRootViewに単体で配置すると呼ばれるという備忘録でした。</description>
    </item>
  </channel>
</rss>
