Skip to content

Build no marker icons before the MarkerListIdentity gate on MapKit - #16

Merged
wf9a5m75 merged 1 commit into
developfrom
fix/mapkit-icon-before-gate
Nov 9, 2026
Merged

wf9a5m75 merged 1 commit into
developfrom
fix/mapkit-icon-before-gate

Conversation

@wf9a5m75

@wf9a5m75 wf9a5m75 commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

なぜ

MapKitMapView.Coordinator.updateContent は、syncMarkers の門番(MarkerListIdentity)に届く前に、毎回全マーカーぶんの辞書を 2 つ作っていました。

  • 各マーカーの state の辞書
  • 各マーカーの BitmapIcon の辞書。@Published の icon を読み、アイコンの無いマーカーには毎回 DefaultMarkerIcon() を新しく作って描いていました。

SwiftUI は body を評価するたび(カメラの移動中も)updateContent を呼ぶので、同じ一覧を送り直しただけでもこの全部を払い、その後で門番が捨てていました。

同じ content で updateContent を 1 回呼ぶコスト(144,183 本、シミュレータ、15 回の最良値、body 評価 1 回ぶん):

Debug Release
4 本に 1 本アイコン無し 2970 ms → 12.6 ms 2608 ms → 0.04 ms
全部アイコン付き 111 ms → 27.0 ms 61 ms → 0.14 ms

何を変えたか

辞書はどちらも要りませんでした。

  • state の辞書は、MapKitMarkerController が直近に処理した一覧から持っているもの(markerStatesById、門番を通ったときに add() より前に同期的に埋まる)の重複でした。これを syncedMarkerState(for:) として出し、そちらを引きます。
  • アイコンの辞書の代わりに、mapView(_:viewFor:) で state からアイコンを読みます。toBitmapIcon() はアイコンごとに描いた画像を持っていて、アイコン無しのマーカーは既定の画像 1 枚を使い回します。
  • 今の state を読むので、in-place でアイコンを変えた後に作り直された annotation view も新しいアイコンになります(以前は最後の body 評価のときのキャッシュの中身でした)。

他の iOS 8 プロバイダはすでに門番が先にあります。

検証

  • 上の計測(シミュレータ、Debug・Release)。
  • iPad 実機(Debug): マーカーの基本ページ・街路樹のページの見た目が直す前と同じ。検証用ページ(コミットしていません)で、同じ id の新しい state と in-place のアイコン変更がどちらも直す前と同じように反映されます。

確認できていないもの

  • iPad 実機の Release での計測。

MapKitMapView.Coordinator.updateContent rebuilt two dictionaries over
every marker on each call, before syncMarkers reached its
MarkerListIdentity gate: one with each marker's state, and one with each
marker's BitmapIcon, which read the @published icon and, for markers
with no icon, made a fresh DefaultMarkerIcon() and drew it again. SwiftUI
calls updateContent on every body evaluation, camera moves included, so
a resent identical list paid for all of it although the gate then threw
the work away.

Cost of one updateContent with the same content, 144,183 markers,
simulator, best of 15:

                         Debug       Release
  1 in 4 with no icon    2970 ms ->  12.6 ms   2608 ms -> 0.04 ms
  every marker an icon    111 ms ->  27.0 ms     61 ms -> 0.14 ms

Neither dictionary is needed. The state cache duplicated what
MapKitMarkerController already keeps from its last processed list
(markerStatesById, filled synchronously when the gate lets a list
through, before add() runs), now exposed as syncedMarkerState(for:). The
icon cache is replaced by reading the icon off the state in
mapView(_:viewFor:); toBitmapIcon() keeps the drawn image per icon, and
the no-icon marker shares one default image. Reading the current state
also means an annotation view recreated after an in-place icon change
shows the new icon, rather than whatever the cache held at the last body
evaluation.

The other iOS providers already put the gate first.

Checked on the iPad (Debug): the marker basic and street tree pages look
the same as before, and on a check page a new marker state under the
same id and an in-place icon change both show up as before.
@wf9a5m75
wf9a5m75 merged commit 2ae413f into develop Nov 9, 2026
2 checks passed
@wf9a5m75
wf9a5m75 deleted the fix/mapkit-icon-before-gate branch November 9, 2026 01:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant