Skip to content

Places: Apple's suggestions while typing, chosen with one tap - #287

Merged
renrenmimi merged 1 commit into
mainfrom
ios-native/place-suggestions-as-you-type
Oct 2, 2026
Merged

renrenmimi merged 1 commit into
mainfrom
ios-native/place-suggestions-as-you-type

Conversation

@renrenmimi

Copy link
Copy Markdown
Owner

Follows #286. Adding a place, and saying where a meetup is, now show Apple Maps' suggestions for the words typed so far, before Return, as Apple Maps does.

What shows

  • Add a Place: places only.
  • A meetup: places and street addresses, in the same Places / Addresses groups as the results. The Use "…" as the address row stays.
  • Return still runs the full search, as before.

Where they come from

  • MKLocalSearchCompleter, which Apple made for this; a search on every key could be throttled.
  • There is one completer per kind, so each suggestion's kind is known without asking Apple again (Core/Maps/PlaceSuggestions.swift, MapKitPlaceSuggester).
  • The words are asked about once they have rested for 0.15 s. An answer for older words never shows over newer ones.
  • MapKit's delegate answers on the main thread. Only plain words cross into the main actor; the completer stays where it was.

Choosing one (ApplePlaceFinder.choose(_:))

  • The suggestion is searched for by its name and address, and what that finds is chosen: the place with its identifier (marked when it is on PetNote already, so Add a Place opens it as before), or the address as Apple writes it.
  • A row shows a spinner while this runs.
  • A place the search no longer finds runs a search for its name instead.
  • An address Apple cannot find falls back to the suggestion's own words.
  • A failure is shown the same way a search failure is.

Also

  • The meetup form scrolls its search field to the top when suggestions arrive, so they show above the keyboard. The field sits low in the form.
  • The stand-in directory now matches a place by its address as well as its name, which a suggestion's search needs. StandInPlaceSuggester answers in the emulator build.
  • AppleMapsDeviceProbeTests gains a check of the real completer and of finding a suggested place. It runs on a real iPhone only, and was not run this time.

Tests

  • PlaceSuggestionsTests (10):
    • the words are asked about after the pause, and only for places in Add a Place;
    • nothing is asked for empty words or for words already searched;
    • an answer for older words is not shown;
    • a place, an address, and the three fallbacks;
    • the stand-in suggester.
  • Earlier, with the 9 suites around place search, guards and localization: 103 tests, 0 failed.
  • UI:
    • testSuggestionsWhileTypingChooseAPlaceOrAnAddress is new.
    • All of PlacesMeetupsUITests and CheckinHistoryUITests passed (22, 0 failed). The tests that touch the search field ran again after the scroll change (6 passed).

Screenshots: ios-native/docs/visual-parity/place-suggestions.jpg.

🤖 Generated with Claude Code

Adding a place and saying where a meetup is now show Apple Maps'
suggestions for the words so far, before Return, as Apple Maps does:
places, and for a meetup street addresses, with the words as typed
still offered as the address. They come from MKLocalSearchCompleter,
which is made for it, one completer per kind so each suggestion's kind
is known; the words are asked about once they rest for 0.15 s, and an
answer for older words never shows over newer ones.

A suggestion chosen is searched for by its name and address, and what
that finds is chosen: the place with its identifier, marked when it is
on PetNote already, or the address as Apple writes it. A place the
search no longer finds searches for its name instead. Return still
searches as before.

The meetup form scrolls its search field to the top when suggestions
arrive, so they show above the keyboard. The stand-in directory now
matches a place by its address as well as its name, as a suggestion's
search needs, and a stand-in suggester answers in the emulator build.
The device probe gains a check of the completer on a real iPhone; it
was not run this time.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 2, 2026 08:17
@vercel

vercel Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
pet-note Ready Ready Preview Oct 2, 2026 8:17am UTC

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7ca914fbc7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +95 to +99
let pause = typingPause
typing = Task { [weak self] in
if pause > .zero { try? await Task.sleep(for: pause) }
guard !Task.isCancelled, let self else { return }
let found = await self.suggester.suggestions(for: text, addresses: self.findsAddresses)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clear suggestions as soon as the input changes

When suggestions for one fragment are already visible and the user continues typing, this branch retains those rows throughout the 150 ms pause and the subsequent MapKit request. During that potentially long interval the rows no longer correspond to the text field, and tapping one can select the previous place or address; it also prevents the meetup's empty-to-nonempty scroll trigger from firing for the replacement list. Clear the existing suggestions before scheduling the request for the new fragment.

Useful? React with 👍 / 👎.

Comment on lines +81 to +84
waiting.removeValue(forKey: key)?.resume(returning: [])
// The same words again: the completer does not answer twice.
if completer.queryFragment == text { return suggestions(from: completer) }
return await withCheckedContinuation { continuation in

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep waiting when an identical fragment is still in flight

If a second request for the same normalized fragment arrives before the first completer callback—for example after adding trailing whitespace or quickly deleting and retyping characters—this removes the only continuation and immediately reads completer.results, which may still be empty or belong to the preceding query. The eventual callback then has no waiter, so the correct suggestions are discarded and the UI stays empty or stale until the text changes again. The same-fragment path needs to distinguish cached completed results from an in-flight request and keep a continuation for the latter.

Useful? React with 👍 / 👎.

@renrenmimi
renrenmimi merged commit ffb3c8d into main Oct 2, 2026
7 checks passed
renrenmimi added a commit that referenced this pull request Oct 2, 2026
STATUS: where a meetup is, one search and suggestions (#286, #287)

This branch was successfully deployed

1 active deployment
Preview — 7ca914fb Deployed Oct 2, 2026 by vercel[bot]
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.

2 participants