0

I’m very new to Swift and Xcode and I’ve built a simple two storyboard app which has a welcome screen and a button that triggers a seque to second storyboard (for which I have created its own class based on UIVIewController. Second storyboard has a couple of UIPickerView objects a and a couple of UIDatePickerView objects and a button. I have some basic actions under the didSelectRow function. However when I build and run the app I get an odd and seemingly random bevahiour where selecting something in the first picker view takes me back to the welcome screen (an unwind seque?). I haven’t put in any code to do that! Any ideas?

import UIKit
class SecondViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
    @IBOutlet weak var cityPicker: UIPickerView!
    @IBOutlet weak var fromDatePicker: UIDatePicker!
    @IBOutlet weak var toDatePicker: UIDatePicker!
    @IBOutlet weak var nextThirdViewButton: UIButton!
    // temporay array for tsting - Populate with sqlite db extract
    var cityData = ["Please select city", "Beijing", "Calcutta", "Detroit", "Edinburgh", "Glasgow", "London", "Manchester", "New  York", "Rio de Janerio", "Washington"]
    // key variables and flags
    var cityPicked = false
    var fromTimePicked = false
    var toTimePicked = false
    var citySelected: String?
    var fromDate: Date?
    var toDate: Date?
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        fromDatePicker.minimumDate = Date()
        toDatePicker.minimumDate = Date()
        fromDate = Date()
        nextThirdViewButton.layer.cornerRadius = 15
        nextThirdViewButton.layer.masksToBounds = true
        cityPicker.delegate = self
        cityPicker.dataSource = self
    }
    //PickerView functions
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return cityData.count
    }
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return cityData[row]
    }
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        //check user has selcted a city from pickerview and set flags accordingly
        if self.cityData[row] != "Please select city" {
            self.citySelected = self.cityData[row]
            self.cityPicked = true
        } else {
            self.citySelected = "Please select city"
            self.cityPicked = false
        }
    }
    @IBAction func fromDatePicked(_ sender: Any) {
        fromDate = fromDatePicker.date
        if toTimePicked == true {
            checkDates(fromDate: fromDate!, toDate: toDate!)
        }
        fromTimePicked = true
    }
    @IBAction func toDatePicked(_ sender: Any) {
        toDate = toDatePicker.date
        checkDates(fromDate: fromDate!, toDate: toDate!)
    }
    //Function to check if 'to date' is earlier than 'from date' and issue alert
    func checkDates (fromDate: Date, toDate: Date) {
        switch toDate.compare(fromDate) {
        case .orderedDescending:
            toTimePicked = true
        case .orderedAscending:
            presentAlert(title: "Date Alert", message: "You can't travel back in time!")
            toTimePicked = false
        default: return
        }
    }
    // Function to move to third storyboard
    @IBAction func nextThirdViewButton(_ sender: Any) {
        if !(cityPicked && fromTimePicked && toTimePicked) {
            presentAlert(title: "You're not ready yet", message: "Please complete choices")
        } else {
            performSegue(withIdentifier: "thirdViewSeque", sender: nil)
        }
    }
    //reusable alert function
    func presentAlert(title: String, message: String) {
        let presentAlert = UIAlertController(title: title, message: message, preferredStyle: .alert)
        let dismissButton = UIAlertAction (title: "Dismiss", style: .cancel, handler: {
            (dateAlert: UIAlertAction) -> Void in
        })
        presentAlert.addAction(dismissButton)
        self.present(presentAlert, animated: true, completion: nil)
    }
}
matt
  • 515,959
  • 87
  • 875
  • 1,141
RobM
  • 111
  • 1
  • 9
  • 1
    Thanks for the guidance Moritz. Tags have been edited. – RobM Oct 21 '18 at 20:07
  • Hi, I've narrowed down the symptoms of the issue above. It seems to only trigger the unexpected behaviour when I change the picker view by one row. Moving two rows up or down doesn't cause the issue but moving one item up or down the list does. Strange and any clues to what I;ve done wroing most welcomed!! – RobM Oct 21 '18 at 21:42
  • Hi Matt, good challenge and fair point :-) I have obviously done something stupid (damn newbies!). Anyway after much struggle, I've managed to post my code in the main question area. For context, the second storyboard for which this is the code is called by a present modal seque by the user pressing the start button on the welcome screen (first storyboard). Currently the third storyboard is just a blank view controller. Hope that helps with analysing what I've done wrong. Cheers Rob – RobM Oct 22 '18 at 16:57
  • Sorry, should have clarified but I deleted my original project and started again (simplifying the design) but the problem still persists with one pickerview. Basically, when I land on the second storyboard, I select a city from the picker view and two dates (start and finish of my visit) from date pickers. If I move through more than one row of the city picker backwards or forwards, that seems fine. But if I change the city by one row only (forward or backward) then my welcome screen presents modally and I have to hit start to get back to the second storyboard. Hope that makes sense? – RobM Oct 22 '18 at 17:12
  • As an aside, I was thinking last night that this behaviour is like a dismiss so i commented out the code for the button and added a self.dismiss command, built the app, and when I click on the button, I go back to the welcome screen. So it seems that the UI PickerView is somehow dismissing the second view controller if I only move one row in the picker. Does that help? – RobM Oct 22 '18 at 17:21
  • OK, just signing up for github and working out how to add my project – RobM Oct 22 '18 at 17:41
  • Hi Matt, well I've learned a huge amount tonight about GitHub, committing etc! Code should now be on GitHub at https://github.com/Maddog64/Wanderer – RobM Oct 22 '18 at 18:50
  • Try just selecting Beijing immediately i.e. don't roll over to Calcutta and releasing the selection. In fact any, single row change seems to trigger the bug. – RobM Oct 22 '18 at 19:19

1 Answers1

0

The problem is that you are using a .partialCurl presented view controller. Don't. You've stumbled on a terrible bug, namely that there is an invisible area of the presented view controller which, if tapped, dismisses the view controller.

I have an elaborate and extremely hacky workaround, though the simplest solution is to avoid .partialCurl entirely. Here it is; put this code into your presented view controller:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    // workaround for curl bug
    if let grs = self.view.gestureRecognizers {
        for g in grs {
            if NSStringFromClass(type(of:g)).hasSuffix("CurlUpTapGestureRecognizer") {
                g.isEnabled = false
            }
        }
    }
}
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Wow, great work! Shame as I like that transition but I'll change to cross dissolve and live with that. Nasty little bug that one! Thanks so much - this has been causing me sleepless nights :-) – RobM Oct 22 '18 at 19:29
  • Well, I've added my hacky workaround, so give it a try and see if it solves it. I like that transition too so I'm sympathetic. – matt Oct 22 '18 at 19:29
  • Nice thanks! I'm guessing the bug isn't well known as I couldn't find anything on google. One to report to Apple? – RobM Oct 22 '18 at 19:44
  • I've reported it every year for years now. It's called out pretty loudly in my book (which is where the workaround comes from) so that's the best I can do in my never-ending fight to save humanity. – matt Oct 22 '18 at 19:53
  • lol. Well you saved me - I can sleep better tonight :-) Now I can dream of my next storyboard :-) – RobM Oct 22 '18 at 20:20