简体   繁体   中英

iOS MapKit completerDidUpdateResults not called

I'm trying to implement address completion in a React Native application by using a native module that uses a MKLocalSearchCompleter . It's a simple enough class with straightforward delegate methods, but I can't seem to get results from my app. Even running the associated Unit Tests won't work, and I'm not sure why.

Whats happening is that I set the .queryFragment property to my partial string, which should automatically kick off the search which informs my delegate when it's completed or if there's an error. I set the delegate appropriately before making the request, but my delegate completerDidUpdateResults(_ completer: MKLocalSearchCompleter) or completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) methods never get called.

The .isSearching property is set to false after initialization, and when I set the .queryFragment is becomes true, so it seems to be working internally. If I create a new project and drag in the exact same class and unit tests the test runs fine and I get my results with no problems and the test completes in ~0.25 seconds, but in my actual Application project the test hits the 30 second timeout and fails before I get a response.

The only other question I could find on this problem was a Apple Developer Forum question explaining my same situation with no responses from September

Here's my code and tests:

class AddressUtils: NSObject, MKLocalSearchCompleterDelegate {

    let searchCompleter = MKLocalSearchCompleter()
    var results: [MKLocalSearchCompletion]?
    var onSuggestionsReceived: (([String]) -> Void)?

    public override init() {
        super.init()
        searchCompleter.delegate = self
    }

    public func getAddressSuggestions(address: String!, completion: @escaping ([String]) -> Void) {
        self.onSuggestionsReceived = completion
        searchCompleter.queryFragment = address
        if searchCompleter.isSearching {
            print("Searching") // Prints
        }
    }

    func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
        self.results = completer.results
        let results = completer.results.flatMap { (result) -> String? in
            return result.title + " " + result.subtitle
        }
        onSuggestionsReceived?(results)
    }

    func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
        onSuggestionsReceived?([])
    }

}

class UtilityTests: XCTestCase {

    func testAddressAutocomplete() {
        let expectation = self.expectation(description: "Perform search")
        let query = "11 Farns"
        let utils = AddressUtils()
        utils.getAddressSuggestions(address: query) { (results) in
            expectation.fulfill()
        }
        wait(for: [expectation], timeout: 30)
    }

}

Not sure if you ever solved this problem but I had the same issue. Managed to fix by ensuring that queryFragment is only set not the main thread.

private let completer: MKLocalSearchCompleter

DispatchQueue.main.async { [weak self] in
    self?.completer.queryFragment = newValue
}

I was able to get this working after a few days of playing around, but it seems to have been related to the tests themselves, rather than with the actual API or implementation. So much for Test-Driven-Development I guess. The issue was that our test target was added separately and was being run as a separate target with its own scheme, rather than by using the 'Test' configuration from the main scheme. Not entirely sure why that made a difference, but that's my best advice if you're stuck on this issue like I was.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM