TableViewController cell not populating data - ios

I can't figure out why the table view controller is not populating with placeMarks.name and coordinates. The user taps a pin on the map and adds the location to the model. Where then it sent to the table view controller, however, it is not displaying the data from the model. Below is my code.
import Foundation
import CoreLocation
class PlaceList : NSObject {
let locations: Places
var coordinate: CLLocationCoordinate2D { return locations.coordinate }
init(point: Places) {
self.locations = point
super.init()
}
var title: String? {
return locations.name
}
var subtitle: String? {
return "(\(locations.coordinate.latitude), \(locations.coordinate.longitude))"
}
}
import CoreLocation
import Foundation
class Places: NSObject {
var name: String
var coordinate: CLLocationCoordinate2D
init(name: String, coordinate: CLLocationCoordinate2D) {
self.name = name
self.coordinate = coordinate
}
}
import UIKit
import MapKit
import CoreLocation
class MapViewController: UIViewController, MKMapViewDelegate,CLLocationManagerDelegate {
var placeModel: PlaceList?
var pointOfInterest: [Places] = []
var poi: [Places] = [] {
didSet {
pointOfInterest = poi
}
}
//Creating mapview object
var mapView: MKMapView!
var geoCoder = CLGeocoder()
//Initial cooridinate
var latitude = 43.136581
var longitude = -87.941101
var latitudeDelta = 0.3
var longitudeDelta = 0.3
//the object that determines the location
let placeManger = CLLocationManager()
//loading the map on the scene
override func loadView() {
super.loadView()
mapView = MKMapView()
view = mapView
placeManger.startUpdatingLocation()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
navigationItem.title = "Travel Wishlist"
navigationController?.navigationBar.prefersLargeTitles = true
navigationController?.navigationBar.barTintColor = .blue
placeManger.delegate = self
placeManger.requestWhenInUseAuthorization()
mapView.delegate = self
navigationItem.rightBarButtonItem = rightBar
navigationItem.leftBarButtonItem = leftBar
mapView.addGestureRecognizer(tapGestrueRecongnizer)
centerMapInInitialCoordinates()
showPointsOfInterestInMap()
}
func showPointsOfInterestInMap() {
mapView.removeAnnotations(mapView.annotations)
for point in poi {
let pin = PlaceList(point: point)
mapView.addAnnotation(pin as! MKAnnotation)
}
}
func centerMapInInitialCoordinates() {
let span:MKCoordinateSpan = MKCoordinateSpan(latitudeDelta: latitudeDelta, longitudeDelta: longitudeDelta)
let region:MKCoordinateRegion = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: latitude, longitude: longitude), span: span)
mapView.setRegion(region, animated: true)
}
var tapGestrueRecongnizer: UITapGestureRecognizer {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(loadPointOfInterests(recongnizer:)))
return tapGesture
}
var rightBar: UIBarButtonItem {
let rightBarButton =
UIBarButtonItem(title: "Find a place to add",
style: .plain, target: self,
action: #selector(rightbarButton))
rightBarButton.tintColor = .white
return rightBarButton
}
var leftBar: UIBarButtonItem {
let leftBarButton =
UIBarButtonItem(title:
"Look up", style: .plain,
target: self, action: #selector(leftButton))
leftBarButton.tintColor = .white
return leftBarButton
}
#objc func leftButton(leftButton: UIBarButtonItem) {
print("Left BarButton")
performSegue(withIdentifier: "place", sender: leftButton)
addPlace()
}
#objc func rightbarButton(right: UIBarButtonItem) {
addPlace()
}
func addPlace(){
// mapView.removeAnnotations(mapView.annotations)
for point in pointOfInterest {
let pin = PlaceList(point: point)
mapView.addAnnotation(pin as! MKAnnotation)
}
filterVisiblePOI()
}
func filterVisiblePOI() {
let visibleAnnotations = self.mapView.annotations(in: self.mapView.visibleMapRect)
var annotations = [PlaceList]()
for visibleAnnotation in visibleAnnotations {
if let annotation = visibleAnnotation as? PlaceList {
annotations.append(annotation)
}
}
}
#objc func loadPointOfInterests(recongnizer:UITapGestureRecognizer) {
let locationPoint = recongnizer.location(in: mapView)
let cooridinate = mapView.convert(locationPoint, toCoordinateFrom: mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = cooridinate
mapView.addAnnotation(annotation)
geoCoder.reverseGeocodeLocation(CLLocation(latitude: cooridinate.latitude, longitude: cooridinate.longitude)) {(placeMarks : [CLPlacemark]?, error: Error?) in
if let placeLocation = placeMarks?[0] {
if error == nil && (placeMarks?.count)! > 0 {
let locationString = " \(placeLocation.name!)"
annotation.coordinate = cooridinate
annotation.title = locationString
print(locationString)
}
for point in self.pointOfInterest {
let pin = PlaceList(point: point)
self.mapView.addAnnotation(pin as! MKAnnotation)
self.poi.append(point)
print(point)
print(self.pointOfInterest)
print(pin)
}
}
}
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
self.navigationItem.rightBarButtonItem?.title = "Find a place to add"
}
private func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
//To Do
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "place" {
let nav = segue.destination as! UINavigationController
let detailViewControll = nav.topViewController as! VisitationTableViewController
for point in pointOfInterest {
let pin = PlaceList(point: point)
mapView.addAnnotation(pin as! MKAnnotation)
detailViewControll.poi = pointOfInterest
}
}
}
}
import Foundation
import UIKit
class VisitationTableViewController: UITableViewController {
var poi: [Places] = []
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
let dissButton = UIBarButtonItem(title: "Done", style: .done
, target: self, action: #selector(dismisController))
self.navigationItem.rightBarButtonItem = dissButton
dissButton.tintColor = .white
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.title = "Visited"
navigationController?.navigationBar.barTintColor = .blue
print("view didload")
print(poi)
}
#objc func dismisController() {
presentingViewController?.dismiss(animated: true, completion: nil)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return poi.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "locationCell", for: indexPath)
let point = poi[indexPath.row]
cell.textLabel?.text = point.name
cell.detailTextLabel?.text = "(\(point.coordinate.latitude), \(point.coordinate.longitude))"
return cell
}
}

You may need
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
self.performSegue(withIdentifier:"place",sender:nil)
}
And make sure segue source is connected to the vc itself ( drag it from yellow roundec icon of mapVC inside IB )

When I ran the code, tapping into the map didn't add any object to pointOfInterest, which you are making a loop on loadPointOfInterests to add an object to poi but its empty, so make sure to add a Place object in poi
In VisitationTableViewController, make sure to add
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "locationCell")
}

Related

IOS Map Pins are not Showing?

I am struggling with my iOS code. The overall goal of the project is to show the pins on the map, I've tried multiple ways to make the pins appear on the map such as the below, I am not sure what I am doing wrong. The code runs fine, the pins are not appearing. I've made changes to my functions but seem to get the same error. Any insight on what I may be missing?
"import UIKit
import MapKit
class MapViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
#IBOutlet weak var logout: UIBarButtonItem!
#IBOutlet weak var refresh: UIBarButtonItem!
#IBOutlet weak var pinDrop: UIBarButtonItem!
var studentLocation = [StudentInformation]()
var annotations = [MKPointAnnotation]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewDidAppear (_ animated: Bool) {
super.viewDidAppear(true)
getStudentPins()
}
#IBAction func refresh(_ sender: UIBarButtonItem) {
getStudentPins ()
}
#IBAction func logout(_ sender: UIBarButtonItem) {
self.activityIndicator.startAnimating()
UdacityClient.logout {
DispatchQueue.main.async {
self.dismiss(animated: true, completion: nil)
self.activityIndicator.stopAnimating()
}
}
}
#IBAction func addLocation(_ sender: Any) {
performSegue(withIdentifier: "addLocation", sender: nil)
}
func getStudentPins () {
self.activityIndicator.startAnimating()
UdacityClient.getStudentLocations() { locations, error in
self.mapView.removeAnnotations(self.annotations)
self.annotations.removeAll()
self.studentLocation = locations ?? []
for dictionary in locations ?? [] {
let latitude = CLLocationDegrees(dictionary.latitude ?? 0.0)
let longitude = CLLocationDegrees(dictionary.longitude ?? 0.0)
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
let firstName = dictionary.firstName
let lastName = dictionary.lastName
let mediaURL = dictionary.mediaURL
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
annotation.title = "\(firstName) \(lastName)"
annotation.subtitle = mediaURL
self.annotations.append(annotation)
}
DispatchQueue.main.async {
self.mapView.addAnnotations(self.annotations)
self.activityIndicator.stopAnimating()
}
}
}
private func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotation? {
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.pinTintColor = .green
pinView!.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
}
else {
pinView!.annotation = annotation
}
return pinView?.annotation
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
if let toOpen = view.annotation?.subtitle {
openLink(toOpen ?? "")
}
}
}
}"
They're called annotations in the MapKit and you should instantiate them like so:
let annotation = MKPointAnnotation()
then in the viewDidLoad() method just set the coordinates and add them to the map like:
annotation.coordinate = CLLocationCoordinate2D(latitude: 11.12, longitude: 12.11)
mapView.addAnnotation(annotation)
The numbers are your coordinates. Try by adding sample coordinates on the map first and then add all coordinates which you are getting from the client.
you can also add more information using:
annotation.title = "Your text here"
//You can also add a subtitle that displays under the annotation such as
annotation.subtitle = "One day I'll go here..."

Update MapView Pin Location

So I have a MapView which adds a pin to the current user location. Also I have two textfields which displays the coordinates of the pin. I want to add two features:
When I drag and drop the pin, I want to update the coordinates inside the textfields.
When I edit the coordinates in the textfield, it should move the pin to the updated coorinates from the textfields.
Here my code where i handle everything for MapView. Im still pretty new to coding, so the code could be confusing, sorry for that.
class LocateVC: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var finishedLocateButton: UIButton!
#IBOutlet weak var relocateButton: UIButton!
var coordinates: [[Double]]!
var latTitleLabel:[String]!
var latValueLabel:[String]!
var lngTitleLabel:[String]!
var lngValueLabel: [String]!
var isEdited = false
var customCallout: UIView?
//Important to track location
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
view.layer.backgroundColor = Colors.grey.cgColor
//button titles
relocateButton.isHidden = true
relocateButton.setTitle("Relocate", for: .normal)
finishedLocateButton.setTitle("Continue", for: .normal)
navigationItem.title = "Location"
// Ask for Authorisation from the User.
self.locationManager.requestAlwaysAuthorization()
self.locationManager.requestWhenInUseAuthorization()
locationManager.delegate = self
self.mapView.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
if isEdited == false {
if CLLocationManager.locationServicesEnabled() {
addPin()
}
}
// Latitude,Longitude
coordinates = [
[ProductData.shared.latitude!, ProductData.shared.longitude!],
]
} //end of viewDidLoad
override func viewWillAppear(_ animated: Bool) {
super.dismiss(animated: animated)
}
public func removePin() {
}
func dropPinFor(placemark: MKPlacemark) {
for annotation in mapView.annotations {
if annotation.isKind(of: MKPointAnnotation.self) {
// mapView.removeAnnotation(annotation) // removing the pins from the map
}
}
let annotation = MKPointAnnotation()
annotation.coordinate = placemark.coordinate
mapView.addAnnotation(annotation)
}
//1
public func addPin() {
if isEdited == false {
ProductData.shared.latitude = locationManager.location?.coordinate.latitude
ProductData.shared.longitude = locationManager.location?.coordinate.longitude
}
self.mapView.delegate = self
// adds an annotation to coordinates from productData
let point = ProductAnnotation(coordinate: CLLocationCoordinate2D(latitude: ProductData.shared.latitude! , longitude: ProductData.shared.longitude!))
self.mapView.addAnnotation(point)
// 3
let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: ProductData.shared.latitude!, longitude: ProductData.shared.longitude!), span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1))
self.mapView.setRegion(region, animated: true)
}
public func editCoord() {
performSegue(withIdentifier: "editCoord", sender: CustomCalloutView.self)
}
#IBAction func relocateButtonClicked(_ sender: Any) {
addPin()
}
#IBAction func finishedLocateButtonClicked(_ sender: Any) {
performSegue(withIdentifier: "finishedLocateSegue2", sender: self)
}
//4
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
if view.isKind(of: CustomCalloutView.self ) || view.isKind(of: AnnotationView.self) || view.isKind(of: ProductAnnotation.self) {
return
} else {
customCallout?.removeFromSuperview()
}
}
//3
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
if view.annotation is MKUserLocation {
return
}
//this creates the callout
let views = Bundle.main.loadNibNamed("CustomCalloutView", owner: nil, options: nil)
let calloutView = views?[0] as! CustomCalloutView
calloutView.delegate = self
calloutView.lngTitleLabel.text = "Lng"
calloutView.latTitleLabel.text = "Lat"
calloutView.lngTextField.text = String(format:"%f", ProductData.shared.longitude!)
calloutView.latTextField.text = String(format:"%f", ProductData.shared.latitude!)
calloutView.latTextField.layer.borderWidth = 0.0
calloutView.lngTextField.layer.borderWidth = 0.0
calloutView.latTextField.isEnabled = false
calloutView.lngTextField.isEnabled = false
calloutView.latTextField.keyboardType = .numberPad
calloutView.lngTextField.keyboardType = .numberPad
calloutView.alpha = 1.0
calloutView.layer.cornerRadius = 8
calloutView.center = CGPoint(x: view.bounds.size.width / 2, y: -calloutView.bounds.size.height*0.52)
customCallout = calloutView
view.addSubview(calloutView)
mapView.setCenter((view.annotation?.coordinate)!, animated: true)
}
//2
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
var annotationView = self.mapView.dequeueReusableAnnotationView(withIdentifier: "Pin")
if annotationView == nil{
annotationView = AnnotationView(annotation: annotation, reuseIdentifier: "Pin")
annotationView?.isDraggable = true
annotationView?.canShowCallout = false
} else {
annotationView?.annotation = annotation
}
annotationView?.image = UIImage(named: "dot")
return annotationView
}
func saveButtonTapped() {
customCallout?.removeFromSuperview()
}
}
extension LocateVC: CustomCalloutViewDelegate {
func didClickEditButton() {
editCoord()
}
func didClickSaveButton() {
saveButtonTapped()
}
}
and here my custom callout:
class CustomCalloutView: UIView {
#IBOutlet weak var latTitleLabel: UILabel!
#IBOutlet weak var lngTitleLabel: UILabel!
#IBOutlet weak var editButton: UIButton!
#IBOutlet weak var saveButton: UIButton!
#IBOutlet weak var latTextField: UITextField!
#IBOutlet weak var lngTextField: UITextField!
var delegate: CustomCalloutViewDelegate?
var isEditing: Bool = false
#IBAction func didClickEditButton(_ sender: Any) {
// delegate?.didClickEditButton()
isEditing = true
latTextField.layer.borderWidth = 1.0
lngTextField.layer.borderWidth = 1.0
latTextField.isEnabled = true
lngTextField.isEnabled = true
saveButton.isHidden = false
}
#IBAction func saveButtonTapped(_ sender: Any) {
if isEditing == true {
if let lat = latTextField.text {
ProductData.shared.latitude = Double(lat)
}
if let lng = lngTextField.text {
ProductData.shared.longitude = Double(lng)
}
latTextField.layer.borderWidth = 0.0
lngTextField.layer.borderWidth = 0.0
latTextField.isEnabled = false
lngTextField.isEnabled = false
self.saveButton.setTitle("Save", for: .normal)
isEditing = false
} else {
self.saveButton.setTitle("Cancel", for: .normal)
delegate?.didClickSaveButton()
}
}
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
if self.bounds.contains(point) {
return true
} else {
return self.subviews.contains { $0.frame.contains(point) }
}
}
}
protocol CustomCalloutViewDelegate {
func didClickEditButton()
func didClickSaveButton()
}
any idea how i can achive that? Maybe in a general way.
Thank you in advance
Here's a link to DSCenterPinMapView. A CocoaPod I recommend you to use.
It is a custom MapView with an animated and customizable center pin useful for selecting locations in map.
Here is also a guide on installing CocoaPods if it is new to you.
You should install the Pod an then, as a solution to your questions:
Implement the delegate so that you can get the location where pin drops.
pinMapView.delegate = self
extension MyViewController: DSCenterPinMapViewDelegate {
func didStartDragging() {
// My custom actions
}
func didEndDragging() {
// My custom actions
selectedLocation = pinMapView.mapview.centerCoordinate
// Update Text field
}
}
After you finish adding the coordinates on your TextFields you should call
pinMapView.center(on coordinate: myTextFieldCoordinate)
to center the map on the desired location.
After changing the marker position get coordinates like
let latitude = marker.coordinate.latitude
let longitude = marker.coordinate.longitude
And to set coordinate
let coordinate = CLLocationCoordinate2D(latitude: "your lat", longitude: "your long")
marker.coordinate = coordinate
mapView.setCenter(coordinate, animated: true)
if you not keeping the marker reference then
guard let marker = self.appleMap.annotations.first else {return}
let latitude = marker.coordinate.latitude
let longitude = marker.coordinate.longitude
And to set coordinate
guard let marker = self.appleMap.annotations.first else {return}
let coordinate = CLLocationCoordinate2D(latitude: "your lat", longitude: "your long")
marker.coordinate = coordinate
mapView.setCenter(coordinate, animated: true)
Hope that will help.

MapKit Map with child view won't add annotations

I'm currently trying to implement a Map connected with a search function. For the overlay containing the table view, I've decided to go for a library called FloatingPanel. Anyways, this shouldn't be of importance, since it shouldn't affect the essential code etc.
The data is being read inside of SearchResultsTableViewController and passed to MapViewController by passData().
Inside of passData() a function called addAnnotationToMap() from MapViewController is being called to process the data - printing inside of the function will always return the correct value.
Inside of the function I'm trying to add an annotation to the map, but it won't work. Nothing happens - but when I do print(mapView.annotations) the Array of annotations is being returned including mine.
By the way, I had to add loadViewIfNeeded() to the MapViewController because without (after using the overlay view) mapView returned nil.
Sorry for the amount of code - but there might be some relevant code. I didn't include the code for the table view.
MapViewController
class MapViewController: UIViewController, FloatingPanelControllerDelegate, UISearchBarDelegate {
var fpc: FloatingPanelController!
var searchVC = SearchResultTableViewController()
private enum AnnotationReuseID: String {
case pin
}
#IBOutlet private var mapView: MKMapView!
var mapItems: [MKMapItem]?
var boundingRegion: MKCoordinateRegion?
override func viewDidLoad() {
super.viewDidLoad()
if let region = boundingRegion {
mapView.region = region
}
fpc = FloatingPanelController()
fpc.delegate = self
// Initialize FloatingPanelController and add the view
fpc.surfaceView.backgroundColor = .clear
fpc.surfaceView.cornerRadius = 9.0
fpc.surfaceView.shadowHidden = false
searchVC = (storyboard?.instantiateViewController(withIdentifier: "SearchPanel") as! SearchResultTableViewController)
// Set a content view controller
fpc.set(contentViewController: searchVC)
fpc.track(scrollView: searchVC.tableView)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Add FloatingPanel to a view with animation.
fpc.addPanel(toParent: self, animated: true)
fpc.move(to: .tip, animated: true)
// Must be here
searchVC.searchController.searchBar.delegate = self
}
func addAnnotationToMap() {
loadViewIfNeeded()
guard let item = mapItems?.first else { return }
guard let coordinate = item.placemark.location?.coordinate else { return }
let annotation = MKPointAnnotation()
annotation.title = item.name
annotation.coordinate = coordinate
mapView.addAnnotation(annotation)
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
searchBar.showsCancelButton = false
fpc.move(to: .tip, animated: true)
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
searchBar.showsCancelButton = true
searchVC.tableView.alpha = 1.0
fpc.move(to: .full, animated: true)
searchVC.hideHeader()
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
fpc.move(to: .half, animated: true)
searchVC.showHeader()
}
func floatingPanelDidMove(_ vc: FloatingPanelController) {
let y = vc.surfaceView.frame.origin.y
let tipY = vc.originYOfSurface(for: .tip)
if y > tipY - 44.0 {
let progress = max(0.0, min((tipY - y) / 44.0, 1.0))
self.searchVC.tableView.alpha = progress
}
}
func floatingPanelWillBeginDragging(_ vc: FloatingPanelController) {
if vc.position == .full {
searchVC.searchBar.showsCancelButton = false
searchVC.searchBar.resignFirstResponder()
}
}
func floatingPanelDidEndDragging(_ vc: FloatingPanelController, withVelocity velocity: CGPoint, targetPosition: FloatingPanelPosition) {
UIView.animate(withDuration: 0.25,
delay: 0.0,
options: .allowUserInteraction,
animations: {
if targetPosition == .tip {
self.searchVC.tableView.alpha = 0.0
self.searchVC.hideHeader()
} else if targetPosition == .half {
self.searchVC.tableView.alpha = 1.0
self.searchVC.showHeader()
} else {
self.searchVC.tableView.alpha = 1.0
self.searchVC.hideHeader()
}
}, completion: nil)
}
}
SearchViewController
class SearchResultTableViewController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var visualEffectView: UIVisualEffectView!
private enum CellReuseID: String {
case resultCell
}
private var places: [MKMapItem]? {
didSet {
tableView.reloadData()
}
}
private var suggestionController: SuggestionsTableTableViewController!
var searchController: UISearchController!
private var localSearch: MKLocalSearch? {
willSet {
places = nil
localSearch?.cancel()
}
}
private var boundingRegion: MKCoordinateRegion?
override func awakeFromNib() {
super.awakeFromNib()
suggestionController = SuggestionsTableTableViewController()
suggestionController.tableView.delegate = self
searchController = UISearchController(searchResultsController: suggestionController)
searchController.searchResultsUpdater = suggestionController
searchController.searchBar.isUserInteractionEnabled = false
searchController.searchBar.alpha = 0.5
}
override func viewDidLoad() {
super.viewDidLoad()
searchBar.addSubview(searchController.searchBar)
searchController.searchBar.searchBarStyle = .minimal
searchController.searchBar.tintColor = .black
searchController.searchBar.isUserInteractionEnabled = true
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
hideHeader()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if #available(iOS 10, *) {
visualEffectView.layer.cornerRadius = 9.0
visualEffectView.clipsToBounds = true
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
func showHeader() {
changeHeader(height: 116.0)
}
func hideHeader() {
changeHeader(height: 0.0)
}
func changeHeader(height: CGFloat) {
tableView.beginUpdates()
if let headerView = tableView.tableHeaderView {
UIView.animate(withDuration: 0.25) {
var frame = headerView.frame
frame.size.height = height
self.tableView.tableHeaderView?.frame = frame
}
}
tableView.endUpdates()
}
func passData() {
guard let mapViewController = storyboard?.instantiateViewController(withIdentifier: "map") as? MapViewController else { return }
guard let mapItem = places?.first else { return }
guard let coordinate = mapItem.placemark.location?.coordinate else { return }
let span = MKCoordinateSpan(latitudeDelta: coordinate.latitude, longitudeDelta: coordinate.longitude)
let region = MKCoordinateRegion(center: coordinate, span: span)
mapViewController.boundingRegion = region
mapViewController.mapItems = [mapItem]
mapViewController.addAnnotationToMap()
}
private func search(for suggestedCompletion: MKLocalSearchCompletion) {
let searchRequest = MKLocalSearch.Request(completion: suggestedCompletion)
search(using: searchRequest)
}
private func search(for queryString: String?) {
let searchRequest = MKLocalSearch.Request()
searchRequest.naturalLanguageQuery = queryString
search(using: searchRequest)
}
private func search(using searchRequest: MKLocalSearch.Request) {
if let region = boundingRegion {
searchRequest.region = region
}
UIApplication.shared.isNetworkActivityIndicatorVisible = true
localSearch = MKLocalSearch(request: searchRequest)
localSearch?.start { [weak self] (response, error) in
if error == nil {
self?.passData()
} else {
self?.displaySearchError(error)
return
}
self?.places = response?.mapItems
self?.boundingRegion = response?.boundingRegion
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
}
private func displaySearchError(_ error: Error?) {
if let error = error as NSError?, let errorString = error.userInfo[NSLocalizedDescriptionKey] as? String {
let alertController = UIAlertController(title: "Could not find any places.", message: errorString, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(alertController, animated: true, completion: nil)
}
}
}

Reference Parameter in Class Swift

I have created the following:
let artworkPin = Artwork(title:"Wind Wand",locationName:"Majestic",discipline:"Statue",
coordinate:windwandcoord)
where Artwork refers to a class located in Artwork.swift, I am trying to assign a label to obtain the title value (Located in a annotation on UI View 1 ) through a Segue to go to a Label ( Located in UI View 2) by doing the following:
#IBOutlet weak var art_title: UILabel!
var viaSegue = "artwork title should be here"
override func viewDidLoad() {
super.viewDidLoad()
art_title.text = viaSegue
but I don't know how to reference it correctly for via Segue to take the value of "title".
ENTIRE FILE:
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate,CLLocationManagerDelegate {
#IBOutlet weak var MapView: MKMapView!
let manager = CLLocationManager()
var artworkPin = Artwork!
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//let location = locations[0]
//let span:MKCoordinateSpan = MKCoordinateSpanMake(0.02, 0.02)
//let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
}
override func viewDidLoad() {
super.viewDidLoad()
// tracking user's location
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
// Setting up Map
let distanceSpan:CLLocationDegrees = 2000
MapView.setRegion(MKCoordinateRegionMakeWithDistance(CLLocationCoordinate2DMake(-39.0556253, 174.0752278), distanceSpan, distanceSpan), animated: true)
MapView.showsUserLocation = true
MapView.delegate = self
// artwork on map
let windwandcoord: CLLocationCoordinate2D = CLLocationCoordinate2DMake(-39.055961,174.072288)
artworkPin = Artwork(title:"Wind Wand",locationName:"Majestic",discipline:"Statue",
coordinate:windwandcoord)
MapView.addAnnotation(artworkPin)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
{
if annotation is MKUserLocation {return nil}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
pinView!.calloutOffset = CGPoint(x: -5, y: 5)
let calloutButton = UIButton(type: .detailDisclosure)
pinView!.rightCalloutAccessoryView = calloutButton
pinView!.sizeToFit()
}
else {
pinView!.annotation = annotation
}
return pinView
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
performSegue(withIdentifier: "no", sender:self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let ViewTwo = segue.destination as! ViewTwo
ViewTwo.artworkPin = self.artworkPin
}
}
Thanks for your help
In your vc B add:
var artworkpin: Artwork!
In your vc A:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vcB = segue.destinationViewController as! vcB
vcB.artworkpin = self.artworkpin
}
after that in vc B viewDidLoad you can get the title by art_title.text = artworkpin.title

How to load a Viewcontroller with Annotation information

I'm building a application that allows people to post annotations on a map and you can click on the detail closure of the annotation and it loads a ViewController with the image and the subtitle information but when I try to load the image and subtitle in the viewDidLoad method of the detailVC it says it's nil
Here's my Annotation code:
extension ViewController: MKMapViewDelegate {
private struct Constants{
static let identifier = "pin"
static let LeftCalloutFrame = CGRect(x:0, y:0, width: 59, height: 59)
static let ShowPinSegueIdentifier = "showDetail"
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? PingAnnotation {
var view = mapView.dequeueReusableAnnotationViewWithIdentifier(Constants.identifier) as? MKPinAnnotationView
if view == nil {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: Constants.identifier)
view?.canShowCallout = true
} else {
view!.annotation = annotation
}
view!.calloutOffset = CGPoint(x: -5, y: 5)
view!.leftCalloutAccessoryView = UIImageView(frame: Constants.LeftCalloutFrame)
view!.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure) as UIView
return view
}
return nil
}
func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
if let thumbnailImageView = view.leftCalloutAccessoryView as? UIImageView {
if let pingAnnotation = view.annotation as? PingAnnotation{
thumbnailImageView.image = pingAnnotation.image
}
}
}
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
performSegueWithIdentifier(Constants.ShowPinSegueIdentifier, sender: view)
}
}
Annotation code:
class PingAnnotation: NSObject, MKAnnotation {
var coordinate : CLLocationCoordinate2D
var title: String?
var subtitle: String?
var image : UIImage?
init(coordinate: CLLocationCoordinate2D, title: String?, subtitle: String?, image: UIImage?) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
self.image = image
}
}
Detail VC Code:
import UIKit
class DetailPingVC: UIViewController {
var ping : PingAnnotation!
#IBOutlet var pingImage: UIImageView!
#IBOutlet var pingDesc: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
pingImage.image = ping.image //shows as nil when ran
pingDesc.text = ping.subtitle //shows as nil when ran
}
#IBAction func pingBtnPressed(sender: AnyObject) {
}
#IBAction func backBtnPressed(sender: AnyObject) {
dismissViewControllerAnimated(true, completion: nil)
}
}
EDIT:
I tried using prepareForSegue but the values still come out nil
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destViewController: DetailPingVC = segue.destinationViewController as! DetailPingVC
destViewController.pingImage.image = ping.image
destViewController.pingDesc.text = ping.subtitle
}
Got it! Basically what I did was add a variable of type string and a variable of type UIImage to the DetailVC and then my prepareForSegue in my viewController looks as so:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destViewController: DetailPingVC = segue.destinationViewController as! DetailPingVC
destViewController.descText = postTextField.text!
destViewController.detailImage = pickImage.image!
}
then in the viewDidLoad of the Detail VC you set the Outlets to the variables you set up earlier.

Resources