I'm creating a map app that autocompletes searches in the search bar. However, the autocomplete results are not displaying.
Here is my code on the ViewController with the mapView:
import UIKit
import MapKit
import CoreLocation
class BarMapVC: UIViewController {
#IBOutlet weak var doneBtn: UIBarButtonItem!
#IBOutlet weak var locationBtn: UIButton!
#IBOutlet weak var barMapView: MKMapView!
var locationManager = CLLocationManager()
let authorizationStatus = CLLocationManager.authorizationStatus()
let regionRadius: Double = 1000
var resultSearchController:UISearchController? = nil
override func viewDidLoad() {
super.viewDidLoad()
barMapView.showsUserLocation = true
barMapView.delegate = self
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
configureLocationServices()
centerMapOnUserLocation()
let locationSearchTable =
storyboard!.instantiateViewController(withIdentifier:
"LocationSearchTable") as! LocationSearchTable
resultSearchController = UISearchController(searchResultsController:
locationSearchTable)
resultSearchController?.searchResultsUpdater = locationSearchTable
let searchBar = resultSearchController!.searchBar
searchBar.sizeToFit()
searchBar.placeholder = "Search for places"
navigationItem.titleView = resultSearchController?.searchBar
resultSearchController?.hidesNavigationBarDuringPresentation = false
resultSearchController?.dimsBackgroundDuringPresentation = true
definesPresentationContext = true
locationSearchTable.mapView = barMapView
}
#IBAction func locationBtnWasPressed(_ sender: Any) {
if authorizationStatus == .authorizedAlways || authorizationStatus
== .authorizedWhenInUse {
centerMapOnUserLocation()
}
}
}
extension BarMapVC: MKMapViewDelegate {
func centerMapOnUserLocation() {
guard let coordinate = locationManager.location?.coordinate else {
return }
let coordinateRegion =
MKCoordinateRegionMakeWithDistance(coordinate, regionRadius * 2.0,
regionRadius * 2.0)
barMapView.setRegion(coordinateRegion, animated: true)
}
}
extension BarMapVC: CLLocationManagerDelegate {
func configureLocationServices() {
if authorizationStatus == .notDetermined {
locationManager.requestAlwaysAuthorization()
} else {
return
}
}
func locationManager(_ manager: CLLocationManager,
didChangeAuthorization status: CLAuthorizationStatus) {
centerMapOnUserLocation()
}
}
And here is my code from the UITableViewController file that displays the autocompleted search results:
import UIKit
import MapKit
class LocationSearchTable : UITableViewController {
var matchingItems:[MKMapItem] = []
var mapView: MKMapView? = nil
func parseAddress(selectedItem:MKPlacemark) -> String {
// put a space between "4" and "Melrose Place"
let firstSpace = (selectedItem.subThoroughfare != nil &&
selectedItem.thoroughfare != nil) ? " " : ""
// put a comma between street and city/state
let comma = (selectedItem.subThoroughfare != nil ||
selectedItem.thoroughfare != nil) && (selectedItem.subAdministrativeArea
!= nil || selectedItem.administrativeArea != nil) ? ", " : ""
// put a space between "Washington" and "DC"
let secondSpace = (selectedItem.subAdministrativeArea != nil &&
selectedItem.administrativeArea != nil) ? " " : ""
let addressLine = String(
format:"%#%#%#%#%#%#%#",
// street number
selectedItem.subThoroughfare ?? "",
firstSpace,
// street name
selectedItem.thoroughfare ?? "",
comma,
// city
selectedItem.locality ?? "",
secondSpace,
// state
selectedItem.administrativeArea ?? ""
)
return addressLine
}
}
extension LocationSearchTable : UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
}
func updateSearchResultsForSearchController(searchController:
UISearchController) {
guard let mapView = mapView,
let searchBarText = searchController.searchBar.text else {
return }
let request = MKLocalSearchRequest()
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
}
override func tableView(_ tableView: UITableView, cellForRowAt
indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
let selectedItem = matchingItems[indexPath.row].placemark
cell.textLabel?.text = selectedItem.name
cell.detailTextLabel?.text = parseAddress(selectedItem:
selectedItem)
return cell
}
}
Is there somewhere I entered an incorrect variable or did something wrong? I've been stuck on this error for two days. Please help thanks!
Related
I have a map search controller that when I search for some annotation, its zooming on it .
Also I would like that when I press the result it will zoom on the correct pin and automatically open the annotationView of the specific annotation
here is my code :
https://github.com/hellzkitchen/stackoverflow-041917.git
import UIKit
import MapKit
class LocationSearchTable : UITableViewController {
var matchingItems = [CustomAnnotations]()
var mapView: MKMapView? = nil
var handleMapSearchDelegate:HandleMapSearch? = nil
func parseAddress(selectedItem:MKPlacemark) -> String {
// put a space between "4" and "Melrose Place"
let firstSpace = (selectedItem.subThoroughfare != nil && selectedItem.thoroughfare != nil) ? " " : ""
// put a comma between street and city/state
let comma = (selectedItem.subThoroughfare != nil || selectedItem.thoroughfare != nil) && (selectedItem.subAdministrativeArea != nil || selectedItem.administrativeArea != nil) ? ", " : ""
// put a space between "Washington" and "DC"
let secondSpace = (selectedItem.subAdministrativeArea != nil && selectedItem.administrativeArea != nil) ? " " : ""
let addressLine = String(
format:"%#%#%#%#%#%#%#",
// street number
selectedItem.subThoroughfare ?? "",
firstSpace,
// street name
selectedItem.thoroughfare ?? "",
comma,
// city
selectedItem.locality ?? "",
secondSpace,
// state
selectedItem.administrativeArea ?? ""
)
return addressLine
}
func search(keywords:String) {
self.matchingItems.removeAll()
for annotation in self.mapView!.annotations {
if annotation.isKindOfClass(CustomAnnotations) {
//Just an example here for searching annotation by title, you could add other filtering actions else.
if (annotation.title??.rangeOfString(keywords) != nil) {
self.matchingItems.append(annotation as! CustomAnnotations)
}
}
}
self.tableView.reloadData()
}
}
extension LocationSearchTable : UISearchResultsUpdating {
func updateSearchResultsForSearchController(searchController: UISearchController) {
guard let mapView = mapView,
let searchBarText = searchController.searchBar.text else { return }
let request = MKLocalSearchRequest()
request.naturalLanguageQuery = searchBarText
request.region = mapView.region
let search = MKLocalSearch(request: request)
search.startWithCompletionHandler { 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
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MapSearchCell", forIndexPath: indexPath)
let selectedItem = matchingItems[indexPath.row]
cell.textLabel?.text = selectedItem.title
cell.detailTextLabel?.text = selectedItem.subtitle
return cell
}
}
extension LocationSearchTable {
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedItem = matchingItems[indexPath.row]//.placemark
handleMapSearchDelegate?.dropPinZoomIn(selectedItem)
dismissViewControllerAnimated(true, completion: nil)
}
}
After you search for a designated annotation, there is a method selectAnnotation:
So when you tap on that result, use
mapView.selectAnnotation(resultAnnotation, animated: true)
I followed a how-to-search-for-location-using-apples-mapkit about searching annotations in mapView
and its searching around the world with MKLocalSearch.
However, I don't want to to search with MKLocalSearch but search my own annotations i added myself like these for example:
let LitzmanLocation = CLLocationCoordinate2DMake(32.100668,34.775192)
// Drop a pin
let Litzman = MKPointAnnotation()
Litzman.coordinate = LitzmanLocation
Litzman.title = "Litzman Bar"
Litzman.subtitle = "נמל תל אביב 18,תל אביב"
mapView.addAnnotation(Litzman)
let ShalvataLocation = CLLocationCoordinate2DMake(32.101145,34.775163)
// Drop a pin
let Shalvata = MKPointAnnotation()
Shalvata.coordinate = ShalvataLocation
Shalvata.title = "Shalvata"
Shalvata.subtitle = "האנגר 28,נמל תל אביב"
mapView.addAnnotation(Shalvata)
let MarkidLocation = CLLocationCoordinate2DMake(32.074961,34.781679)
// Drop a pin
let Markid = MKPointAnnotation()
Markid.coordinate = MarkidLocation
Markid.title = "Markid"
Markid.subtitle = "אבן גבירול 30,תל אביב"
mapView.addAnnotation(Markid)
Here is my Code:
MapViewController.Swift:
import UIKit
import MapKit
import CoreLocation
protocol HandleMapSearch {
func dropPinZoomIn(placemark:MKPlacemark)
}
class MapViewController: UIViewController,MKMapViewDelegate, CLLocationManagerDelegate,UISearchBarDelegate{
#IBOutlet var mapView: MKMapView!
var resultSearchController:UISearchController? = nil
var selectedPin:MKPlacemark? = nil
#IBAction func MapSearchController(sender: AnyObject) {
resultSearchController!.hidesNavigationBarDuringPresentation = false
self.resultSearchController!.searchBar.delegate = self
presentViewController(resultSearchController!, animated: true, completion: nil)
self.resultSearchController!.searchBar.barTintColor = UIColor.blackColor()
self.resultSearchController!.searchBar.placeholder = "חפש ברים"
self.resultSearchController!.dimsBackgroundDuringPresentation = true
self.resultSearchController!.searchBar.sizeToFit()
}
override func viewDidLoad() {
super.viewDidLoad()
let locationSearchTable = storyboard!.instantiateViewControllerWithIdentifier("LocationSearchTable") as! LocationSearchTable
resultSearchController = UISearchController(searchResultsController: locationSearchTable)
resultSearchController?.searchResultsUpdater = locationSearchTable
locationSearchTable.mapView = mapView
locationSearchTable.handleMapSearchDelegate = self
}
}
}
extension MapViewController: HandleMapSearch {
func dropPinZoomIn(placemark:MKPlacemark){
// cache the pin
selectedPin = placemark
// clear existing pins
mapView.removeAnnotations(mapView.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)"
}
mapView.addAnnotation(annotation)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegionMake(placemark.coordinate, span)
mapView.setRegion(region, animated: true)
}
}
LocalSearchTable.Swift:
import UIKit
import MapKit
class LocationSearchTable : UITableViewController {
var matchingItems:[MKMapItem] = []
var mapView: MKMapView? = nil
var handleMapSearchDelegate:HandleMapSearch? = nil
func parseAddress(selectedItem:MKPlacemark) -> String {
// put a space between "4" and "Melrose Place"
let firstSpace = (selectedItem.subThoroughfare != nil && selectedItem.thoroughfare != nil) ? " " : ""
// put a comma between street and city/state
let comma = (selectedItem.subThoroughfare != nil || selectedItem.thoroughfare != nil) && (selectedItem.subAdministrativeArea != nil || selectedItem.administrativeArea != nil) ? ", " : ""
// put a space between "Washington" and "DC"
let secondSpace = (selectedItem.subAdministrativeArea != nil && selectedItem.administrativeArea != nil) ? " " : ""
let addressLine = String(
format:"%#%#%#%#%#%#%#",
// street number
selectedItem.subThoroughfare ?? "",
firstSpace,
// street name
selectedItem.thoroughfare ?? "",
comma,
// city
selectedItem.locality ?? "",
secondSpace,
// state
selectedItem.administrativeArea ?? ""
)
return addressLine
}
}
extension LocationSearchTable : UISearchResultsUpdating {
func updateSearchResultsForSearchController(searchController: UISearchController) {
guard let mapView = mapView,
let searchBarText = searchController.searchBar.text else { return }
let request = MKLocalSearchRequest()
request.naturalLanguageQuery = searchBarText
request.region = mapView.region
let search = MKLocalSearch(request: request)
search.startWithCompletionHandler { 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
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MapSearchCell")!
let selectedItem = matchingItems[indexPath.row].placemark
cell.textLabel?.text = selectedItem.name
cell.detailTextLabel?.text = parseAddress(selectedItem)
return cell
}
}
extension LocationSearchTable {
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedItem = matchingItems[indexPath.row].placemark
handleMapSearchDelegate?.dropPinZoomIn(selectedItem)
dismissViewControllerAnimated(true, completion: nil)
}
}
you just refer to this link
http://www.coderzheaven.com/2016/02/14/mapkit-demo-swift-annotation-custom-annotation-custom-annotation-with-button-search-showing-directions-apple-maps-ios/
you will understand the following topics
Show Annotation in Maps.
Show Custom Annotation in Maps.
Show Custom Annotation with Custom Button in Maps.
TL;DR
Example project: https://github.com/JakubMazur/SO40539590
Ok, so for the beginning I will suggest you separate data from your controller code. I choose json format as most universal one. So:
[
{
"title":"Litzman Bar",
"subtitle":"נמל תל אביב 18,תל אביב",
"coordinates":{
"lat":32.100668,
"lon":34.775192
}
},
{
"title":"Shalvata",
"subtitle":"האנגר 28,נמל תל אביב",
"coordinates":{
"lat":32.101145,
"lon":34.775163
}
},
{
"title":"Markid",
"subtitle":"אבן גבירול 30,תל אביב",
"coordinates":{
"lat":32.074961,
"lon":34.781679
}
}
]
This is basically your database.
Now let's parse it into an Array to use inside your ViewConttroller. Again I will suggest you split it into Model objects like Location and Coordinate. Let's have a look in one class of it as example:
class Location: NSObject {
var title : String = String()
var subtitle : String = String()
var coordinates : Coordinate = Coordinate()
public class func locationFromDictionary(_ dictionary : Dictionary<String, AnyObject>) -> Location {
let location : Location = Location()
location.title = dictionary["title"] as! String
location.subtitle = dictionary["subtitle"] as! String
location.coordinates = Coordinate.coordinateFromDictionary(dictionary["coordinates"] as! Dictionary<String, AnyObject>)
return location;
}
}
I will not paste the code for parsing json file to this objects, because that's what is not this question is about. You will find in into repository.
And now let's focus on question.
I will recommend you not to search annotations, but search your data model and redraw annotations when needed
In order to do that (i will use UISearchBar for it):
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
self.displayArray = self.locationsDatabase.filter() {
return $0.title.contains("i")
}
Then when you ovverride a setter like this:
var displayArray : Array<Location> = [] {
didSet {
self.mapView .removeAnnotations(self.mapView.annotations)
for location in displayArray {
let coords : Coordinate = location.coordinates
let point = MKPointAnnotation()
point.coordinate = CLLocationCoordinate2DMake(CLLocationDegrees(coords.latitude),CLLocationDegrees(coords.longitude))
point.title = location.title
point.subtitle = location.subtitle
mapView.addAnnotation(point)
}
}
}
You can redraw your annotations. The edge cases like empty search field, case sensivity, dismissing keyboard I leave to you. But hope you will get the general idea. You may think that it's overengineered but having objects as a separate classes and universal format as an data input may benefit in the future.
Full project: https://github.com/JakubMazur/SO40539590
I try to sort my tableView by distance form the current location. I search on the website but is it very difficult for me to adapte on my projet what I find
Can you help me please?
Here is my first files for data "Cables.swift":
import Foundation
import MapKit
class Person {
var identifier:Int
var name:String
var country:String
var email:String
var website:String
var facebook:String
var adress:String
var phone:String
var latitude:Double
var longitude:Double
var lac:Int
var poulie1:Int
var rotation1:String
var module1:Int
var poulie2:Int
var rotation2:String
var module2:Int
var distance:Double
var smallPhotoUrl:URL! {
return URL(string: "http://wakefinder.16mb.com/full/\(self.identifier).jpg")
}
var largePhotoUrl:URL! {
return URL(string: "http://wakefinder.16mb.com/full/\(self.identifier).jpg")
}
//var coordinate: CLLocationCoordinate2D
init?(fromData personData:[String:AnyObject]) {
guard let identifier = personData["id"] as? Int,
let name = personData["name"] as? String,
let country = personData["country"] as? String,
let email = personData["email"] as? String,
let website = personData["website"] as? String,
let facebook = personData["facebook"] as? String,
let adress = personData["adress"] as? String,
let phone = personData["phone"] as? String,
let latitude = personData["lat"] as? Double,
let longitude = personData["lng"] as? Double,
let lac = personData["lac"] as? Int,
let poulie1 = personData["poulie1"] as? Int,
let rotation1 = personData["rotation1"] as? String,
let module1 = personData["module1"] as? Int,
let poulie2 = personData["poulie2"] as? Int,
let rotation2 = personData["rotation2"] as? String,
let module2 = personData["module2"] as? Int
else {
return nil
}
self.identifier = identifier
self.name = name
self.country = country
self.email = email
self.website = website
self.facebook = facebook
self.adress = adress
self.phone = phone
self.latitude = latitude
self.longitude = longitude
self.lac = lac
self.poulie1 = poulie1
self.rotation1 = rotation1
self.module1 = module1
self.poulie2 = poulie2
self.rotation2 = rotation2
self.module2 = module2
}
// Function to calculate the distance from given location.
func calculateDistance(fromLocation: CLLocation?) {
let location = CLLocation(latitude: self.latitude, longitude: self.longitude)
distance = location.distance(from: fromLocation!)
}
}
and the file for my TableView:
import UIKit
import Alamofire
import CoreLocation
class cableViewController: UITableViewController, UISearchResultsUpdating {
var _personList:[Person] = []
var _personFiltered:[Person] = []
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
Alamofire.request("http://wakefinder.16mb.com/users.json")
.validate()
.responseJSON { (response) in
if response.result.isSuccess {
let rawPersonList = response.result.value as! [[String:AnyObject]]
for personData in rawPersonList {
if let personObject = Person(fromData: personData) {
self._personList.append(personObject)
}
}
self.tableView.reloadData()
} else {
print(response.result.error as Any)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController.isActive && searchController.searchBar.text != "" {
return _personFiltered.count
}
return _personList.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:cablesTableViewCell! = tableView.dequeueReusableCell(withIdentifier: "cable_cell") as! cablesTableViewCell
if searchController.isActive && searchController.searchBar.text != "" {
let person:Person = _personFiltered[indexPath.row]
cell.display(person: person)
//_personList[indexPath.row] = _personFiltered[indexPath.row]
} else {
let person:Person = _personList[indexPath.row]
cell.display(person: person)
}
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
if let cell = sender as? UITableViewCell {
if let indexPath = self.tableView.indexPath(for: cell) {
let selectedPerson: Person
if searchController.isActive && searchController.searchBar.text != "" {
selectedPerson = _personFiltered[indexPath.row]
} else {
selectedPerson = _personList[indexPath.row]
}
let personViewController:fichesViewController = segue.destination as! fichesViewController
personViewController._person = selectedPerson
}
}
}
}
func updateSearchResults(for searchController: UISearchController) {
filterContent(searchText: self.searchController.searchBar.text!)
}
func filterContent(searchText:String) {
_personFiltered = _personList.filter { user in
let username = user.name
return(username.lowercased().contains(searchText.lowercased()))
}
self.tableView.reloadData()
}
}
Any idea how i can be making this GET request with Alamofire - getting exactly what I want back - passing the info to the func tableView(tableView: UITableView - populating and returning each cell and yet my table, simply, will not show the loaded data?
From within the AlamoFire promised return i call self.refresh() which calls this in the main thread:
func refresh() {
dispatch_async(dispatch_get_main_queue(),{
self.tableView.reloadData()
});
--
Any ideas? This is literally driving me nuts. Thanks for any ideas or solutions in advance!
import UIKit
import Alamofire
import MapKit
class ListViewController: UIViewController, UISearchBarDelegate, CLLocationManagerDelegate, UITableViewDelegate, UITableViewDataSource {
var tools = [Tool]()
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
let locationManager = CLLocationManager()
var currentLat: CLLocationDegrees = 0.0
var currentLong: CLLocationDegrees = 0.0
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
searchBar.delegate = self
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 116
self.tableView.registerClass(ToolTableViewCell.self, forCellReuseIdentifier: "ToolTableViewCell")
self.locationManager.delegate = self
self.locationManager.requestAlwaysAuthorization()
self.locationManager.requestWhenInUseAuthorization()
// if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = manager.location!.coordinate
// print("locations = \(locValue.latitude) \(locValue.longitude)")
let location = locations.last! as CLLocation
currentLat = location.coordinate.latitude
currentLong = location.coordinate.longitude
}
func searchBarSearchButtonClicked(searchbar: UISearchBar)
{
searchbar.resignFirstResponder()
tools = []
let defaults = NSUserDefaults.standardUserDefaults()
let userid: Int = defaults.objectForKey("toolBeltUserID") as! Int
let searchTerm = String(searchBar.text!)
print(searchTerm)
Alamofire.request(.GET, "http://localhost:3000/tools/search", parameters: ["keyword": searchTerm, "latitude": currentLat, "longitude": currentLong,
"user": userid]) .responseJSON {response in
if let JSON = response.result.value {
print("\(JSON)")
for i in 0 ..< JSON.count {
let owner = JSON[i].objectForKey("owner")
let tool = JSON[i].objectForKey("tool")
let title = tool!["title"] as! String!
let ownerId = owner!["id"] as! Int!
let distanceToTool = JSON[i].objectForKey("distance") as! Double
var description: String
if let des = tool!["description"] as? NSNull {
description = ""
} else {
description = (tool!["description"] as? String!)!
}
let myTool = Tool(title: title!, description: description, ownerId: ownerId!, distance: distanceToTool)
self.tools.append(myTool)
}
// dispatch_async(dispatch_get_main_queue(), {
self.refresh()
// })
} else {
print("Sent search term, but no response")
}
}
}
func refresh() {
dispatch_async(dispatch_get_main_queue(),{
self.tableView.reloadData()
});
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(tools.count)
return tools.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "ToolTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as!ToolTableViewCell
let tool = tools[indexPath.row]
if(indexPath.row==0){
cell.title?.text = tool.title
// print(tool.title)
// cell.toolListDescription?.text = tool.description
cell.ownerId = tool.ownerId
// print(tool.ownerId)
// print(tool.distance)
// cell.distance?.text = "\(tool.distance)mi"
}
print(cell)
return cell
}
}
make sure you set the Reuse Identifier in the attribute inspector! in my case it was 'ToolTableViewCell'
Thanks!
I have a problem presenting a view controller with a Mapkit inside. The first time I presented it works ok, but when I presented again it throw an EXC_BAD_ACCESS ERROR. Programming language is swift. Any help is appreciated.
Xcode 6.4. iOS 8
ViewController.swift
#IBAction func OnClickTallaCamiseta(sender: AnyObject)
{
txtTallaCamiseta.endEditing(true);
//ocultarTallaCamiseta();
self.performSegueWithIdentifier("mostrarMapa", sender: self)
}
func hecho(controller: MapaController, ciudad: String, departamento: String, pais: String)
{
navigationController?.setNavigationBarHidden(true, animated: true);
ciudadSeleccionada = ciudad;
departamentoSeleccionado = departamento;
paisSeleccionado = pais;
var label:String = "";
if(ciudadSeleccionada != "NO_DATA")
{
label += ciudadSeleccionada;
}
if(departamentoSeleccionado != "NO_DATA")
{
label += ", " + departamentoSeleccionado;
}
if(paisSeleccionado != "NO_DATA")
{
label += ", " + paisSeleccionado;
}
lblCiudadEres.text = label;
self.navigationController?.popViewControllerAnimated(true);
}
func terminado(controller: MapaController)
{
println("terminado");
navigationController?.setNavigationBarHidden(true, animated: true);
self.navigationController?.popViewControllerAnimated(true);
}
MapaController.swift
import Foundation
import UIKit
import GoogleMaps
import MapKit
import CoreLocation
protocol MapaControllerDelegate
{
func terminado(controller:MapaController);
func hecho(controller:MapaController, ciudad:String, departamento:String, pais:String);
}
class MapaController : UIViewController, UITableViewDataSource, UITableViewDelegate,
GPSDelegate, MKMapViewDelegate
{
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var btnDone: UIBarButtonItem!
#IBOutlet weak var txtSearch: UITextField!
var locationManager:CLLocationManager = CLLocationManager();
var camera:GMSCameraPosition? = nil;
var aqui:CLLocationCoordinate2D? = nil;
var ne:CLLocationCoordinate2D? = nil;
var sw:CLLocationCoordinate2D? = nil;
var bounds:GMSCoordinateBounds? = nil;
var placesClient:GMSPlacesClient = GMSPlacesClient();
var data:[GMSAutocompletePrediction] = [GMSAutocompletePrediction]();
var ciudad = "";
var departamento = "";
var pais = "";
var delegate:MapaControllerDelegate? = nil;
var gps = GPSLocation;
let filter = GMSAutocompleteFilter();
required init(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
}
override func viewDidLoad()
{
super.viewDidLoad();
placesClient = GMSPlacesClient();
filter.type = GMSPlacesAutocompleteTypeFilter.Geocode;
self.tableView.dataSource = self;
self.tableView.delegate = self;
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell");
self.tableView.hidden = true;
self.btnDone.enabled = false;
navigationController?.setNavigationBarHidden(false, animated: true);
//setMarkerAndMoveCamera(gps.lat, longitud: gps.long);
gps.gpsDelegate = self;
println("TERMINA"); }
#IBAction func OnTextChanged(sender: AnyObject)
{
if(!txtSearch.text.isEmpty)
{
//println("Searching for '\(self.txtSearch.text)'");
placesClient.autocompleteQuery(self.txtSearch.text,
bounds: bounds,
filter: filter,
callback: { (results, error) -> Void in
if error != nil
{
println("Autocomplete error \(error) for query '\(self.txtSearch.text)'")
return
}
//println("Populating results for query '\(self.txtSearch.text)'");
self.data = [GMSAutocompletePrediction]();
for result in results!
{
if let result = result as? GMSAutocompletePrediction
{
self.data.append(result)
}
}
self.tableView.reloadData();
self.tableView.hidden = false;
if(!self.btnDone.enabled)
{
self.btnDone.enabled = true;
}
});
}
else
{
self.data = [GMSAutocompletePrediction]()
self.tableView.reloadData()
self.tableView.hidden = true;
}
}
func CoordUpdated(latitud: Double, longitud: Double)
{
moverCamara(latitud, longitud: longitud);
aqui = CLLocationCoordinate2DMake(latitud, longitud);
ne = CLLocationCoordinate2DMake(aqui!.latitude + 1, aqui!.longitude + 1);
sw = CLLocationCoordinate2DMake(aqui!.latitude - 1, aqui!.longitude - 1);
bounds = GMSCoordinateBounds(coordinate: ne!, coordinate: sw!);
}
func CoordenadasGuardadas(exito: Bool){}
func VisitaMarcada(exito: Bool){}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return self.data.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell;
cell.textLabel?.text = self.data[indexPath.row].attributedFullText.string;
return cell;
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
txtSearch.text = self.data[indexPath.row].attributedFullText.string;
txtSearch.endEditing(true);
var placeId:String = self.data[indexPath.row].placeID;
tableView.hidden = true;
placesClient.lookUpPlaceID(placeId,
callback: {(place, error) -> Void in
if error != nil
{
println("lookup place id query error: \(error!.localizedDescription)")
return
}
if place != nil
{
var coordenada:CLLocationCoordinate2D = place!.coordinate;
var lat = coordenada.latitude;
var long = coordenada.longitude;
self.setMarkerAndMoveCamera(lat, longitud: long);
var array = split(self.data[indexPath.row].attributedFullText.string) {$0 == ","};
if(array.count == 3)
{
self.ciudad = array[0];
self.departamento = array[1];
self.pais = array[2];
}
else if(array.count == 2)
{
self.ciudad = array[0];
self.departamento = "NO_DATA";
self.pais = array[1];
}
else
{
self.ciudad = array[0];
self.departamento = "NO_DATA";
self.pais = "NO_DATA";
}
}
else
{
println("No place details for \(placeId)")
}
});
}
func moverCamara(latitud:Double, longitud:Double)
{
/*let location = CLLocationCoordinate2D(latitude: latitud, longitude: longitud)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegion(center: location, span: span)
mapa.setRegion(region, animated: true)*/
}
func setMarkerAndMoveCamera(latitud:Double, longitud:Double)
{
/*let location = CLLocationCoordinate2D(latitude: latitud, longitude: longitud)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegion(center: location, span: span)
mapa.setRegion(region, animated: true)
let annotationsToRemove = self.mapa.annotations.filter { $0 !== self.mapa.userLocation }
mapa.removeAnnotations( annotationsToRemove )
let annotation = MKPointAnnotation()
annotation.coordinate = location;
annotation.title = NSLocalizedString("label_ciudad_encontrada",comment:"label_ciudad_encontrada");
mapa.addAnnotation(annotation);*/
}
#IBAction func OnDone(sender: AnyObject)
{
delegate?.hecho(self, ciudad: ciudad, departamento: departamento, pais: pais);
}
#IBAction func OnCancel(sender: AnyObject)
{
delegate?.terminado(self);
}
override func viewWillDisappear(animated:Bool)
{
self.tableView.delegate = nil;
}
#IBAction func onCancelar(sender: AnyObject)
{
delegate?.terminado(self);
}
}
you need to identify the cell, in this case with "cell".
select your tableview, next select prototype cells to 1 in attributes inspector.
Expand the Table View, and select the viewCell
In option the option "identifier" put "cell".