I am newbie in Swift development. I need help to pass in data when the annotation view is clicked. When annotation view is clicked it goes to a view controller called DetailsViewController, but not data is being passed. Can anyone help me solve this by passing in some data/details in my view controller. Thank you for the help. PS: I learn from other developers code. :-).
Here is my code:
import UIKit
import MapKit
protocol UserLocationDelegate {
func userLocation(latitude :Double, longitude :Double)
}
class NearMeMapViewController: ARViewController, ARDataSource, MKMapViewDelegate, CLLocationManagerDelegate {
var nearMeIndexSelected = NearMeIndexTitle ()
var locationManager : CLLocationManager!
var nearMeARAnnotations = [ARAnnotation]()
var nearMeRequests = [NearMeRequest]()
var delegate : UserLocationDelegate!
var place: Place?
override func viewDidLoad() {
super.viewDidLoad()
self.title = nearMeIndexSelected.indexTitle
self.locationManager = CLLocationManager ()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.distanceFilter = kCLHeadingFilterNone
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.dataSource = self
self.headingSmoothingFactor = 0.05
self.maxVisibleAnnotations = 30
getNearMeIndexSelectedLocation()
}
func getNearMeIndexSelectedLocation()
{
let nearMeRequest = MKLocalSearchRequest()
nearMeRequest.naturalLanguageQuery = nearMeIndexSelected.indexTitle
let nearMeregion = MKCoordinateRegionMakeWithDistance(self.locationManager.location!.coordinate, 250, 250)
nearMeRequest.region = nearMeregion
let nearMeSearch = MKLocalSearch(request: nearMeRequest)
nearMeSearch.start { (response : MKLocalSearchResponse?, error :Error?) in
for requestItem in (response?.mapItems)! {
let nearMeIndexRequest = NearMeRequest ()
nearMeIndexRequest.name = requestItem.name
nearMeIndexRequest.coordinate = requestItem.placemark.coordinate
nearMeIndexRequest.address = requestItem.placemark.addressDictionary?["FormattedAddressLines"] as! [String]
nearMeIndexRequest.street = requestItem.placemark.addressDictionary?["Street"] as! String!
nearMeIndexRequest.city = requestItem.placemark.addressDictionary?["City"] as! String
nearMeIndexRequest.state = requestItem.placemark.addressDictionary?["State"] as! String
nearMeIndexRequest.zip = requestItem.placemark.addressDictionary?["ZIP"] as! String
self.nearMeRequests.append(nearMeIndexRequest)
print(requestItem.placemark.name)
}
for nearMe in self.nearMeRequests {
let annotation = NearMeAnnotation(nearMeRequest: nearMe)
self.nearMeARAnnotations.append(annotation)
self.setAnnotations(self.nearMeARAnnotations)
}
}
}
Update you tapBlurButton func
func tapBlurButton(_ sender: UITapGestureRecognizer) {
if let annotationView = sender.view as? NearMeARAnnotationView {
if let detailsVc = storyboard?.instantiateViewController(withIdentifier: "DetailsViewController")
as? DetailsViewController {
detailsVc.place = Place(location: (locationManager.location)!,
reference: "",
name: annotationView.annotationNameLabel.text ?? "",
address: annotationView.annotationAddressLabel.text ?? "")
self.navigationController?.pushViewController(detailsVc, animated: true)
}
}
}
Update your NearMeARAnnotationView class
class NearMeARAnnotationView: ARAnnotationView, CLLocationManagerDelegate {
var annotation: ARAnnotation! //<= ADD this variable.
//>>Other code here
init(annotation : ARAnnotation) {
super .init()
self.annotation = annotation //<= pass data to your new var
//>>Other initialization code here
}
//>> Other code here
}
Update your Details vc code
class DetailsViewController: BaseViewController, UITableViewDelegate, UITableViewDataSource{
var annotation: ARAnnotation!
//>> Other code here
}
Update your new tapBlurButton func
func tapBlurButton(_ sender: UITapGestureRecognizer) {
if let annotationView = sender.view as? NearMeARAnnotationView {
if let detailsVc = storyboard?.instantiateViewController(withIdentifier: "DetailsViewController")
as? DetailsViewController {
detailsVc.annotation = annotationView.annotation
detailsVc.place = Place(location: (locationManager.location)!,
reference: "",
name: annotationView.annotationNameLabel.text ?? "",
address: annotationView.annotationAddressLabel.text ?? "")
self.navigationController?.pushViewController(detailsVc, animated: true)
}
}
}
An then in your DetailsVC you should be able to access all the data which was in your annotation passed to your NearMeARAnnotationView in this way:
let name = annotation.name
let address = annotation.address
directly in DetailsVC
Related
I am creating an app where I have annotation view and when you click on the annotation view it does not show the annotation view website url on the view controller DetailsView please have a look at my code and help me solve it by showing the website URL of the annotation view places.
Here is my code:
import UIKit
import MapKit
protocol UserLocationDelegate {
func userLocation(latitude: Double, longitude: Double)
}
class NearMeMapViewController: ARViewController, ARDataSource, MKMapViewDelegate, CLLocationManagerDelegate {
var nearMeIndexSelected = NearMeIndexTitle()
var locationManager: CLLocationManager!
var nearMeARAnnotations = [ARAnnotation]()
var nearMeRequests = [NearMeRequest]()
var delegate: UserLocationDelegate!
var place: Place?
override func viewDidLoad() {
super.viewDidLoad()
self.title = nearMeIndexSelected.indexTitle
self.locationManager = CLLocationManager()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.distanceFilter = kCLHeadingFilterNone
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.dataSource = self
self.headingSmoothingFactor = 0.05
self.maxVisibleAnnotations = 30
getNearMeIndexSelectedLocation()
}
func getNearMeIndexSelectedLocation() {
let nearMeRequest = MKLocalSearchRequest()
nearMeRequest.naturalLanguageQuery = nearMeIndexSelected.indexTitle
let nearMeregion = MKCoordinateRegionMakeWithDistance(self.locationManager.location!.coordinate, 250, 250)
nearMeRequest.region = nearMeregion
let nearMeSearch = MKLocalSearch(request: nearMeRequest)
nearMeSearch.start{(response: MKLocalSearchResponse?, error: Error?) in
for requestItem in (response?.mapItems)! {
let nearMeIndexRequest = NearMeRequest()
nearMeIndexRequest.name = requestItem.name
nearMeIndexRequest.coordinate = requestItem.placemark.coordinate
nearMeIndexRequest.address = requestItem.placemark.addressDictionary?["FormattedAddressLines"] as! [String]
nearMeIndexRequest.street = requestItem.placemark.addressDictionary?["Street"] as! String!
nearMeIndexRequest.city = requestItem.placemark.addressDictionary?["City"] as! String
nearMeIndexRequest.state = requestItem.placemark.addressDictionary?["State"] as! String
nearMeIndexRequest.zip = requestItem.placemark.addressDictionary?["ZIP"] as! String
nearMeIndexRequest.phone = requestItem.phoneNumber
nearMeIndexRequest.website = requestItem.website // This is where the error is at.
self.nearMeRequests.append(nearMeIndexRequest)
print(requestItem.placemark.name)
}
for nearMe in self.nearMeRequests {
let annotation = NearMeAnnotation(nearMeRequest: nearMe)
self.nearMeARAnnotations.append(annotation)
self.setAnnotations(self.nearMeARAnnotations)
}
}
}
func ar(_ arViewController: ARViewController, viewForAnnotation: ARAnnotation) -> ARAnnotationView {
let annotationView = NearMeARAnnotationView(annotation: viewForAnnotation)
annotationView.frame = CGRect(x: 0, y: 0, width: 150, height: 50)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.tapBlurButton(_:)))
annotationView.addGestureRecognizer(tapGesture)
return annotationView
}
func tapBlurButton(_ sender: UITapGestureRecognizer) {
if let annotationView = sender.view as? NearMeARAnnotationView {
if let detailsVc = storyboard?.instantiateViewController(withIdentifier: "DetailsViewController") as? DetailsViewController {
detailsVc.annotation = annotationView.annotation
detailsVc.place = Place(location: (locationManager.location)!,
reference: "",
name: annotationView.annotationNameLabel.text ?? "",
address: annotationView.annotationAddressLabel.text ?? "",
phoneNumber: annotationView.phoneNumber.text ?? "",
website: annotationView.website.text ?? "")
self.navigationController?.pushViewController(detailsVc, animated: true)
}
}
}
}
There isn't a website property on MKMapItem. There is a url property however that should contain the website associated with the location.
Here is what Apple's docs say about the map item's url property.
If there is a relevant URL associated with the location, such as a URL for a business at the location, use this property to specify that value.
Your line of code:
nearMeIndexRequest.website = requestItem.website
should be changed to:
nearMeIndexRequest.website = requestItem.url.absoluteString
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()
}
}
I'm designing an app which has the a feature to let user add their own pin. Recently, I found my app has a memory leak with the title of "ContiguousArrayStorage". I debugged a little and figured out it was a problem with my for loop in my viewdidload, but I am not sure how to fix the leak.
Here is my code:
#IBOutlet weak var AppleMap: MKMapView!
#IBOutlet weak var LogoutOutlet: UIButton!
#IBOutlet weak var OutletforAddPokemon: UIButton!
#IBOutlet weak var FindLocationOutlet: UIButton!
#IBOutlet weak var FilterOutlet: UIButton!
let locationManager = CLLocationManager()
let calendar: NSCalendar! = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
var increment:Int = 0
var currentLoc:CLLocationCoordinate2D?
var centerMap = true
let StoringPin = FIRDatabase.database().reference().child("locations")
var Date = NSDate()
override func viewDidLoad() {
super.viewDidLoad()
AppleMap.delegate = self
StoringPin.observeEventType(.Value, withBlock: {
snapshot in
if snapshot.value is NSNull {
return
}
let val = snapshot.value as! [String : [String : AnyObject]]
for key in val.keys {
let latitudedata = val[key]!["latitude"] as! Double
let longitudedata = val[key]!["longitude"] as! Double
let namedata = val[key]!["name"] as! String
let Username = val[key]!["Username"]
as! String
let DATE = val[key]!["Date"]
as! String
let NumberOflikesforuser = val[key]!["Likes"] as! Int
let NumberOfDislikesforuser = val[key]!["Dislikes"] as! Int
let coord = CLLocationCoordinate2D(latitude: latitudedata, longitude: longitudedata)
let artwork = Capital(title: "\(namedata)", coordinate: coord, info: "HI", username: Username, NumofLikes: NumberOflikesforuser,NumofDisLikes: NumberOfDislikesforuser, UIDSTring: UID, date: DATE, color: MKPinAnnotationColor.Green)
artwork.subtitle = DATE
print("k")
let permastringforemail:String = Username
print(++self.increment)
print(UID)
print(permastringforemail)
stringforemail = permastringforemail
Arrayforpins.append(artwork)
self.AppleMap.addAnnotation(Arrayforpins[Arrayforpins.count - 1])
for Capital in Arrayforpins {
self.AppleMap.addAnnotation(Capital)
}
}
})
print(LogoutOutlet)
LogoutOutlet.layer.cornerRadius = 4
FindLocationOutlet.layer.cornerRadius = 4
OutletforAddPokemon.layer.cornerRadius = 4
//FilterOutlet.layer.cornerRadius = 4
self.locationManager.requestAlwaysAuthorization()
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
let annotationView = MKAnnotationView()
let detailButton: UIButton = UIButton.init(type: .DetailDisclosure) as UIButton
annotationView.rightCalloutAccessoryView = detailButton
}
let regionRadius: CLLocationDistance = 1000
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
regionRadius * 2.0, regionRadius * 2.0)
AppleMap.setRegion(coordinateRegion, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = manager.location!.coordinate
if CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse {
AppleMap.showsUserLocation = true
} else {
locationManager.requestWhenInUseAuthorization()
}
print("update")
currentLoc = locValue
if centerMap {
centerMap = false
centerMapOnLocation(CLLocation(latitude: currentLoc!.latitude, longitude: currentLoc!.longitude))
}
}
#IBAction func SendtoSelector(sender: AnyObject) {
self.performSegueWithIdentifier("SeguetoSelector", sender: self)
}
#IBAction func FilterFunc(sender: AnyObject) {
self.performSegueWithIdentifier("SeguetoFilter", sender: self)
}
#IBAction func FindLocation(sender: AnyObject) {
centerMapOnLocation(CLLocation(latitude: currentLoc!.latitude, longitude: currentLoc!.longitude))
}
#IBAction func Logout(sender: AnyObject) {
LO = true
self.performSegueWithIdentifier("BacktoLoginScreen", sender: self)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
locationManager
if IndexBoolean == true{
//let annotationView = MKPinAnnotationView()
print("Hi")
let artwork = Capital(title: "\(pickerDataSource[chosenindex])", coordinate: CLLocationCoordinate2D(latitude: currentLoc!.latitude, longitude: currentLoc!.longitude), info: "HEY", username: stringforemail, NumofLikes: NumberOfLikes, NumofDisLikes: NumberOfDislike, UIDSTring: UID, date: stringfordate2, color: MKPinAnnotationColor.Green)
//print(now)
print(chosenindex)
artwork.title = "\(pickerDataSource[chosenindex])"
//artwork.subtitle = stringfordate
AppleMap.addAnnotation(artwork)
//annotationView.pinColor = artwork.Green
Arrayforpins.append(artwork)
print(stringforemail)
AppleMap.addAnnotation(Arrayforpins[Arrayforpins.count - 1])
for Capital in Arrayforpins{
AppleMap.addAnnotation(Capital)
}
IndexBoolean = false
var formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
formatter.timeZone = NSTimeZone(abbreviation: "Central Time")
var utcTimeZoneSTR = formatter.stringFromDate(Date)
stringfordate = "\(utcTimeZoneSTR)"
let uid = NSUUID().UUIDString
UID = uid
StoringPin.child(uid).setValue(["name" : pickerDataSource[chosenindex],
"latitude" : currentLoc!.latitude,
"longitude" : currentLoc!.longitude,"Array Position" : chosenindex,"Username": stringforemail, "Likes": NumberOfLikes2, "Dislikes":
NumberOfDislike, "UID": UID, "Date": stringfordate])
if FilterBoolean == true {
print("b")
if FilterDataSource[Intforfilter] != stringforname {
print("k")
//self.AppleMap.viewForAnnotation(artwork)?.hidden = true
FilterBoolean == false
}
//else {
// print("m")
// self.AppleMap.removeAnnotation(artwork)
//
// }
FilterBoolean == false
}
}
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "Capital"
print(++increment)
if annotation.isKindOfClass(Capital.self) {
print("CAPITAL")
if let annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) {
annotationView.annotation = annotation
return annotationView
} else {
let annotationView = MKPinAnnotationView(annotation:annotation, reuseIdentifier:identifier)
annotationView.enabled = true
annotationView.canShowCallout = true
//annotationView.pinColor = MKPinAnnotationColor.Green
let btn = UIButton(type: .DetailDisclosure)
annotationView.rightCalloutAccessoryView = btn
return annotationView
}
}
return nil
}
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let capital = view.annotation as! Capital
let placeName = capital.title
let placeInfo = capital.info
let UserName = capital.username
stringforname = view.annotation!.title!!
coords = view.annotation!.coordinate
stringforemail = capital.username
stringfordate2 = capital.date
NumberOfLikes2 = capital.NumofLikes
UID = capital.UIDSTring
print(stringforname)
print(UID)
self.performSegueWithIdentifier("SegueToInfo", sender: self)
}
I note you're not taking care to specify how to capture self in your closure. When in a disposable object context (a UIViewController) and an async closure you always have to worry about this. You need to capture it as weak or unowned. Are you familiar with closure capture lists?
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID56
The pattern I use is to capture self weakly and then bail if self has become nil, e.g. the UIViewController has been dismissed and harvested. If it is still around, I temporarily capture it strongly with a local variable in a guard...let statement.
withBlock: { [weak self] (snapshot) in
guard let s = self else {
print("Callback called after view unloaded")
return
}
// now use 's' instead of 'self'
...
}
Can't say this is the only problem because we don't have the declarations for your helper classes. For example we don't know what mischief Capital is up to.
By the way, just be clear that your for loop does not run at viewDidLoad(). You're merely registering a callback that only reacts if and when the .Value event occurs on the StoringPin object.
For some odd reason the viewForAnnotation is only working for the pin that is set in viewDidLoad (this is a test pin). The pins that are loaded elsewhere aren't getting annotated when pressed. I've already set the delegate. I think it has something to do with the identifier in the mapView call? But I'm unsure of how to fix it. Any help is appreciated! Thanks!
Here's my code:
import Foundation
import UIKit
import MapKit
import CoreLocation
import Alamofire
class MapViewController: UIViewController, MKMapViewDelegate {
var locationManager:CLLocationManager = CLLocationManager()
#IBOutlet weak var potholeMapView: MKMapView!
var listData: Array<String> = []
var idData: Array<Int> = []
var descriptionData: Array<String> = []
var latitudeData:Array<Double> = []
var longitudeData:Array<Double> = []
override func viewDidLoad() {
super.viewDidLoad()
potholeMapView.delegate = self
locationManager.requestWhenInUseAuthorization()
potholeMapView!.region = sanDiegoCountyLocation()
potholeMapView!.mapType = MKMapType.Standard
potholeMapView!.showsUserLocation = true
potholeMapView!.showsTraffic = true
print(potholeMapView!.userLocationVisible)
// WORKING HERE ACCESSORY VIEW SHOWS
let encinitas = CLLocationCoordinate2DMake(32.955, -117.2459)
let marker = AnnotatedLocation(
coordinate: encinitas,
title: "There",
subtitle: "You are not here")
potholeMapView!.addAnnotation(marker)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//HERE ACCESSORY VIEWS DONT SHOW
loadPotholeData()
}
func sanDiegoCountyLocation()-> MKCoordinateRegion {
let center = CLLocationCoordinate2DMake(32.76572795, -117.07319880 )
let widthMeters:CLLocationDistance = 100
let heightMeters:CLLocationDistance = 1000*120
return MKCoordinateRegionMakeWithDistance(center, widthMeters, heightMeters)
}
func loadPotholeData(){
let url = "http://bismarck.sdsu.edu/city/fromDate"
let parametersGet = ["type" : "street", "user" : "008812"]
Alamofire.request(.GET, url, parameters: parametersGet)
.responseJSON { response in
if let dataGet = response.result.value {
let dataDict:NSArray = dataGet as! NSArray
for item in dataDict{
let descrip = item["created"]
self.listData.append(descrip!! as! String)
let ids = item["id"]
self.idData.append(ids! as! Int)
let description = item["description"]
self.descriptionData.append(description!! as! String)
let latitude = item["latitude"]
self.latitudeData.append(latitude as! Double)
let longitude = item["longitude"]
self.longitudeData.append(longitude as! Double)
}
}
else {
print("There was some error getting data")
}
}
createAllPins()
}
func createAllPins(){
for (x, y) in zip(self.latitudeData, self.longitudeData) {
let location = CLLocationCoordinate2DMake(x, y)
let marker = AnnotatedLocation(
coordinate: location,
title: "",
subtitle: "")
potholeMapView!.addAnnotation(marker)
}
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? AnnotatedLocation {
let identifier = "pin"
var view: MKPinAnnotationView
if let dequeuedView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
as? MKPinAnnotationView {
dequeuedView.annotation = annotation
view = dequeuedView
} else {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
//view = MKPinAnnotationView(annotation: <#T##MKAnnotation?#>, reuseIdentifier: <#T##String?#>)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
view.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
}
return view
}
return nil
}
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
self.performSegueWithIdentifier("pushAnnotation", sender: view)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let identifier = segue.identifier {
switch identifier {
case "pushAnnotation":
let nextVC = segue.destinationViewController as! MapAnnotationDetailViewController
//nextVC.
default: break
}
}
}
}
It appears that it is because your title and subtitle for the others are blank. I tested out having nothing in quotations and adding something, and that seems to fix that issue.
For me, it was that after specifying my custom mapView.mapType, I had to also tell the mapView to "showAnnotations".
Until I told it to show them, the annotations would not display.
mapView.mapType = mapTypes[Preference.mapType]
mapView.showAnnotations(mapView.annotations, animated: true) //this fixed it