[英]UI Tableview won't display or update search results in cells, Swift
I am an intermediate Swift developer and I am creating an app that involves using a search function to find an address and pinpoint said address on a map.我是一名中级 Swift 开发人员,我正在创建一个应用程序,该应用程序涉及使用搜索 function 来查找地址并在 map 上查明所述地址。 I followed a tutorial on how to achieve this and everything is functional besides the search function itself.
我遵循了一个关于如何实现这一点的教程,除了搜索 function 本身之外,一切都正常。 Whenever I type in the UIsearchbar my search results tableview controller is instantiated, however, the table view is blank and does not update as I type.
每当我在 UIsearchbar 中键入时,我的搜索结果 tableview controller 都会被实例化,但是,table view 是空白的,并且在我键入时不会更新。 An address API call should be present.
应该存在地址 API 调用。
import UIKit
import MapKit
class LocationSearchTable : UITableViewController {
var resultSearchController:UISearchController? = nil
var handleMapSearchDelegate:HandleMapSearch? = nil
var matchingItems:[MKMapItem] = []
var mapView: MKMapView? = nil
@IBOutlet var searchTableView: UITableView!
}
extension LocationSearchTable : UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
searchController.showsSearchResultsController = true
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
guard let mapView = mapView,
let searchBarText = searchController.searchBar.text else { return }
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = searchBarText
request.region = mapView.region
let search = MKLocalSearch(request: request)
search.start { response, _ in
guard let response = response
else {
return
}
self.matchingItems = response.mapItems
self.tableView.reloadData()
}
}
}
extension LocationSearchTable {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return matchingItems.count
}
func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
let selectedItem = matchingItems[indexPath.row].placemark
cell.textLabel?.text = selectedItem.name
cell.detailTextLabel?.text = ""
return cell
}
}
extension LocationSearchTable {
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedItem = matchingItems[indexPath.row].placemark
handleMapSearchDelegate?.dropPinZoomIn(placemark: selectedItem)
dismiss(animated: true, completion: nil)
}
}
import UIKit
import MapKit
import CoreLocation
protocol HandleMapSearch {
func dropPinZoomIn(placemark:MKPlacemark)
}
//for some reason my location delegate is not working (resolved)
class locationViewController: UIViewController, UISearchResultsUpdating, UISearchBarDelegate {
func updateSearchResults(for searchController: UISearchController) {
return
}
var selectedPin:MKPlacemark? = nil
var resultSearchController:UISearchController? = nil
@IBOutlet weak var eventLocationMapView: MKMapView!
@IBOutlet weak var backButton: UIButton!
let locationManager = CLLocationManager()
let regionInMeters: Double = 10000
override func viewDidLoad() {
super.viewDidLoad()
resultSearchController?.searchResultsUpdater = self
let locationSearchTable = storyboard!.instantiateViewController(withIdentifier: "LocationSearchTable") as! LocationSearchTable
resultSearchController = UISearchController(searchResultsController: locationSearchTable)
resultSearchController?.searchResultsUpdater = locationSearchTable
resultSearchController?.searchBar.delegate = self
locationSearchTable.mapView = eventLocationMapView
let searchBar = resultSearchController!.searchBar
searchBar.sizeToFit()
searchBar.placeholder = "Search for places"
//this is the search bar
navigationItem.titleView = resultSearchController?.searchBar
resultSearchController?.hidesNavigationBarDuringPresentation = false
resultSearchController?.obscuresBackgroundDuringPresentation = true
definesPresentationContext = true
locationSearchTable.handleMapSearchDelegate = self
//all of this is in regards to the search functionality
locationManager.startUpdatingLocation()
self.checkLocationAuthorization()
self.checkLocationServices()
self.navigationController?.isNavigationBarHidden = false
// Do any additional setup after loading the view.
locationManager.requestWhenInUseAuthorization()
//this pushes the user request. The issue was most likely in the switch statement
locationManager.delegate = self
locationManager.requestLocation()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
//solved it but we will probably have to go back to this
self.centerViewOnUserLocation()
}
@IBAction func backButtonTapped(_ sender: Any) {
self.transitionBackToCreateEventVC()
}
func transitionBackToCreateEventVC (){
let createEventViewController = self.storyboard?.instantiateViewController(identifier: "createEventVC")
self.view.window?.rootViewController = createEventViewController
self.view.window?.makeKeyAndVisible()
}
func centerViewOnUserLocation() {
if let location = locationManager.location?.coordinate {
let region = MKCoordinateRegion.init(center: location, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
eventLocationMapView.setRegion(region, animated: true)
//this function centers the map onto the location of the user
}
}
func setUpLocationManager(){
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
}
func checkLocationServices(){
if CLLocationManager.locationServicesEnabled(){
setUpLocationManager()
checkLocationAuthorization()
} else {
//show alert letting the user know they have to turn this on
}
}
func checkLocationAuthorization() {
let locationManager = CLLocationManager()
switch locationManager.authorizationStatus {
case .authorizedWhenInUse:
eventLocationMapView.showsUserLocation = true
// We want the users location while the app is in use
break
case .denied:
//show alert instructing how to turn on permissions
break
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
return
case .restricted:
//show an alert
break
case .authorizedAlways:
// we don't want this
break
@unknown default:
return
//I dont know if we need this code
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
extension locationViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse {
locationManager.requestLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
let region = MKCoordinateRegion(center: location.coordinate, latitudinalMeters: 0.05 , longitudinalMeters: 0.05)
eventLocationMapView.setRegion(region, animated: true)
}
}
public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("error:: \(error)")
}
}
extension locationViewController: HandleMapSearch {
func dropPinZoomIn(placemark:MKPlacemark){
// cache the pin
selectedPin = placemark
// clear existing pins
eventLocationMapView.removeAnnotations(eventLocationMapView.annotations)
let annotation = MKPointAnnotation()
annotation.coordinate = placemark.coordinate
annotation.title = placemark.name
if let city = placemark.locality,
let state = placemark.administrativeArea {
annotation.subtitle = "\(city) \(state)"
}
eventLocationMapView.addAnnotation(annotation)
let span = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
let region = MKCoordinateRegion(center: placemark.coordinate, span: span)
eventLocationMapView.setRegion(region, animated: true)
}
}
I think the you should make a property to hold the MKLocalSearch
object in your LocationSearchTable
class.我认为您应该在
LocationSearchTable
class 中创建一个属性来保存MKLocalSearch
object。
class LocationSearchTable : UITableViewController {
private var search: MKLocalSearch?
// ...
}
extension LocationSearchTable : UISearchResultsUpdating {
func updateSearchResultsForSearchController(searchController: UISearchController) {
guard let mapView = mapView,
let searchBarText = searchController.searchBar.text else { return }
// if there is an ongoing search, cancel it first.
self.search?.cancel()
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = searchBarText
request.region = mapView.region
let search = MKLocalSearch(request: request)
search.start { response, error in
guard let response = response
else {
return
}
self.matchingItems = response.mapItems
self.tableView.reloadData()
}
// make sure `search` is not released.
self.search = search
}
}
The problem of the original code is that, the search
object, instance of MKLocalSearch
class will be released when finishes executing updateSearchResultsForSearchController
method, since there is no strong reference to it, and start
's callback will never be called, so your table view will never be reloaded.原代码的问题是,
search
object,MKLocalSearch 实例MKLocalSearch
将在执行完updateSearchResultsForSearchController
方法后被释放,因为没有强引用它,并且start
的回调永远不会被调用,所以你的表视图将永远不会重新加载。
What we do is just make a strong ref to it, and make sure it is not released before completion handler is called.我们所做的只是对其进行强引用,并确保在调用完成处理程序之前它不会被释放。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.