I’m constructing a SwiftUI kind that ought to autocomplete road addresses the identical manner Apple Maps does.
I’m utilizing MKLocalSearchCompleter, however its delegate strategies are by no means known as, so no options seem (not even in Xcode’s console). I reproduced the difficulty in a brand-new venture with solely the code under.
What I anticipate
Because the consumer sorts into the TextField, MKLocalSearchCompleter ought to name completer(_:didUpdateResults:), and tackle options ought to be listed under the sphere.
What truly occurs
• The question string updates accurately (verified with print).
• completer(:didUpdateResults:) and completer(:didFailWithError:) are by no means invoked.
• No options are proven.
Minimal reproducible instance
AddressSearchVM.swift
import SwiftUI
import MapKit
last class AddressSearchVM: NSObject, ObservableObject, MKLocalSearchCompleterDelegate {
@Printed var question = "" {
didSet {
// Replace the search fragment at any time when the consumer sorts
if question.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
completer.queryFragment = ""
outcomes = []
} else {
completer.queryFragment = question
}
print("Question modified to: (question)")
}
}
@Printed var outcomes: [MKLocalSearchCompletion] = []
non-public let completer = MKLocalSearchCompleter()
override init() {
tremendous.init()
completer.delegate = self
completer.resultTypes = [.address]
completer.pointOfInterestFilter = .excludingAll
// Broad area protecting the continental US
completer.area = MKCoordinateRegion(
middle: CLLocationCoordinate2D(latitude: 39.8283, longitude: -98.5795),
span: MKCoordinateSpan(latitudeDelta: 50.0, longitudeDelta: 60.0)
)
}
// MARK: -- MKLocalSearchCompleterDelegate
func completer(_ completer: MKLocalSearchCompleter,
didUpdateResults outcomes: [MKLocalSearchCompletion]) {
print("Obtained outcomes: (outcomes.map { $0.title })")
DispatchQueue.fundamental.async {
self.outcomes = Array(outcomes.prefix(5))
}
}
func completer(_ completer: MKLocalSearchCompleter,
didFailWithError error: Error) {
print("Autocomplete error: (error.localizedDescription)")
DispatchQueue.fundamental.async {
self.outcomes = []
}
}
// MARK: -- Helpers
func clearResults() {
outcomes = []
question = ""
}
}
ContentView.swift (related half)
struct ContentView: View {
@StateObject non-public var addressVM = AddressSearchVM()
@FocusState non-public var focus: Area?
@State non-public var showingSuggestions = false
@State non-public var pickupAddress = ""
enum Area { case tackle }
var physique: some View {
Kind {
Part("Pickup Handle") {
HStack {
Picture(systemName: "mappin.and.ellipse")
.foregroundColor(.secondary)
TextField("123 Instance St", textual content: $addressVM.question)
.targeted($focus, equals: .tackle)
.onChange(of: addressVM.question) { _, newValue in
showingSuggestions = !newValue.isEmpty && focus == .tackle
if newValue.isEmpty { pickupAddress = "" }
}
.onChange(of: focus) { _, newFocus in
showingSuggestions = newFocus == .tackle && !addressVM.question.isEmpty
}
}
if showingSuggestions && !addressVM.outcomes.isEmpty {
VStack(alignment: .main, spacing: 0) {
ForEach(addressVM.outcomes, id: .self) { merchandise in
Button {
let full = merchandise.title + (merchandise.subtitle.isEmpty ? "" : ", (merchandise.subtitle)")
pickupAddress = full
addressVM.question = full
showingSuggestions = false
focus = nil
} label: {
VStack(alignment: .main, spacing: 2) {
Textual content(merchandise.title)
if !merchandise.subtitle.isEmpty {
Textual content(merchandise.subtitle).font(.caption).foregroundColor(.secondary)
}
}
.padding(.vertical, 8)
.body(maxWidth: .infinity, alignment: .main)
}
.buttonStyle(.plain)
if merchandise != addressVM.outcomes.final { Divider() }
}
}
}
}
}
}
}
Issues I’ve tried
- 1.New clean venture with solely this code → identical conduct.
- Completely different simulators (iPhone 14 / 15) and an actual gadget → no change.
- Commented out the customized area (let Apple select default) → no change.
- Added specific calls to startUpdatingLocation() by way of CLLocationManager to ensure location providers have been lively → nonetheless no delegate callbacks.
Any perception or workaround could be enormously appreciated.
Thanks prematurely!