I've searched around and can't seem to find an answer to why my segue is loading the next view controller twice. For some reason it only happens occasionally, I'd say around 1/5 times the getMyLocation
button is pressed. What I would like to happen is the user press getMylocation
and from there grab the user's coordinates, store the data, and present the next view with the stored data. Because of this, I have performSegue
in didUpdatedLocations
so that I can store the data before calling the segue. I should note that the segue was created in the storyboard by ctrl click and dragging my main view to the next one, not by dragging a button.
My code first the first view:
// Declare all IB Outlets
@IBOutlet weak var cityLabel: SpringTextField!
@IBOutlet weak var stateLabel: SpringTextField!
@IBOutlet weak var searchButton: SpringButton!
@IBOutlet weak var getLocationButton: SpringButton!
@IBOutlet weak var locationButton: UIButton!
@IBOutlet weak var citySearchButton: UIButton!
// Declare all variables
var latAndLong = ""
var city = ""
var state = ""
let locationManager = CLLocationManager()
let limitLength = 2
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let locValue: CLLocationCoordinate2D = manager.location?.coordinate else { return }
let lat = locValue.latitude
let long = locValue.longitude
latAndLong = "\(lat),\(long)"
locationManager.stopUpdatingLocation()
self.performSegue(withIdentifier: "goToSecond", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
// Declare text label delegates to allow control
cityLabel.delegate = self as UITextFieldDelegate
stateLabel.delegate = self as UITextFieldDelegate
// Define what tap to look for
let tap : UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
// Delgate Location Manager
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
}
// Allow keyboard to switch text fields from city to state by pressing return
internal func textFieldShouldReturn(_ textField : UITextField) -> Bool {
if textField == cityLabel {
city = cityLabel.text!
textField.resignFirstResponder()
stateLabel.becomeFirstResponder()
}
if textField == stateLabel {
state = stateLabel.text!
performSegue(withIdentifier: "goToSecond", sender: self)
}
return true
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
var newLength = 0
if textField == stateLabel {
guard let text = textField.text else { return true }
newLength = text.count + string.count - range.length
return newLength <= 2
}
else if textField == cityLabel {
guard let text = textField.text else { return true }
newLength = text.count + string.count - range.length
return newLength <= 40
}
return true
}
// Location manager required function + store location variables + perform transition to next view
// Defines what happens when either "Get My Location" or "Search by city is pressed"
@IBAction func getMyLocationPressed(_ sender: Any) {
city = ""
state = ""
let status = CLLocationManager.authorizationStatus()
if status == .authorizedWhenInUse {
locationManager.startUpdatingLocation()
}
else if status == .notDetermined {
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
return
}
else if status == .denied || status == .restricted {
let alert = UIAlertController(title : "Location Services Disabled", message: "Please enable location, or search by City and State", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK",style: .default, handler: nil)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
return
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("didnt work")
}
@IBAction func getLocationPressed(_ sender: SpringButton) {
let status = CLLocationManager.authorizationStatus()
if status == .notDetermined {
locationManager.requestWhenInUseAuthorization()
return
}
else if status == .denied || status == .restricted {
let alert = UIAlertController(title : "Location Services Disabled", message: "Please enable location, or search by City and State", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK",style: .default, handler: nil)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
return
}
locationManager.startUpdatingLocation()
}
// Defines what happens during transition to next screen including what variables to send ober
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToSecond" {
let nextVC = segue.destination as! SecondViewController
nextVC.cityAndState = (city) + "," + (state)
nextVC.latAndLong = latAndLong
}
}
}
And my code for my second view:
var latAndLong = ""
var cityAndState = ""
@IBOutlet weak var tableView: UITableView!
var selectedRow = ""
var namesOfPictures = ["Activities-1", "Food", "Drinks", "Random"]
let display = ["Activities", "Food", "Drink", "Random"]
let cellColors = ["#4D606E","#3FBAC2","#D3D4D8","#F5F5F5"]
override func viewDidLoad() {
super.viewDidLoad()
configureTableView()
tableView.separatorStyle = .singleLine
tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "realCell")
tableView.delegate = self
tableView.dataSource = self
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "realCell", for: indexPath) as! TableViewCell
cell.backgroundView = UIImageView(image: UIImage(named: namesOfPictures[indexPath.row]))
cell.label.text = display[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return display.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(latAndLong)
selectedRow = display[indexPath.row]
print(selectedRow)
tableView.deselectRow(at: indexPath, animated: true)
performSegue(withIdentifier: "goToActivities", sender: self)
}
func configureTableView() {
tableView.rowHeight = 152.0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToActivities" {
let nextVC = segue.destination as! ActivitiesViewController
nextVC.selectedItem = selectedRow
nextVC.cityAndState = cityAndState
nextVC.latAndLong = latAndLong
}
}
CLLoction manager delegate - "didUpdateLocations:" will fire more than once even after stoping location update
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
You have to set delegate to nil after getting a valid user location
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//After validating user location
locationManager.delegate = nil