Search code examples
swiftxcodeuser-interfaceuipickerviewfreeze

UIPickerView freezes UI when reloaded


The ui of my app freezes when the index of the UIPickerView gets to 1 or the number of elements is 2. Im really confused because this was working then all the sudden its broken. Ive done some research and found it may be something to do with a thread. Can someone help me solve the issue with the UIPickerView?

// class implements UIPickerViewDelegate, UIPickerViewDataSource, UIGestureRecognizerDelegate

     @IBOutlet weak var planetPickerView: UIView!
     var planetPicker: UIPickerView!

View did load:

override func viewDidLoad() {
     super.viewDidLoad()
     //Other code not important 
     configurePlanetPicker()
}

UIPickerView implementation: (skyBalls is an array of classes whit various data as getters)

 func configurePlanetPicker() {
        planetPicker = UIPickerView(frame: CGRect(x: 0, y: 0, width: planetPickerView.frame.width, height: 70))
        planetPicker.delegate = self
        planetPicker.dataSource = self
        planetPicker.transform = CGAffineTransform(rotationAngle: CGFloat(-90 * (Double.pi/180)))
        planetPicker.frame = CGRect(x: -100, y: 0, width: planetPickerView.frame.width + 200, height: 70)
        planetPicker.showsSelectionIndicator = false
        planetPickerView.backgroundColor = .clear
        let tap = UITapGestureRecognizer(target: self, action: #selector(pickerTapped))
        tap.delegate = self
        planetPicker.addGestureRecognizer(tap)
        planetPickerView.addSubview(planetPicker)
    }

    func numberOfComponents(in pickerView: UIPickerView) -> Int { return 1 }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {return skyBalls.count }

    func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { return 70 }

    func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat { return 70 }

    func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
        let mainView = UIView(frame: CGRect(x: 0, y: 0, width: 70, height: 70))

        let image = UIImageView(frame: CGRect(x: 15, y: 10, width: 40, height: 40))
        image.image = UIImage(named: "\(skyBalls[row].getImage().split(separator: ".")[0])")
        image.contentMode = .scaleAspectFit
        mainView.addSubview(image)

        let titleLbl = UILabel(frame: CGRect(x: 0, y: 50, width: 70, height: 20))
        titleLbl.text = skyBalls[row].getName()
        titleLbl.textColor = .white
        titleLbl.textAlignment = .center
        titleLbl.adjustsFontSizeToFitWidth = true
        mainView.addSubview(titleLbl)

        mainView.transform = CGAffineTransform(rotationAngle: 90 * CGFloat((Double.pi/180)))
        return mainView
    }

    @objc func pickerTapped(tapRecognizer: UITapGestureRecognizer) {
        if tapRecognizer.state == .ended {
            let rowHeight = planetPicker.rowSize(forComponent: 0).height
            let selectedRowFrame = planetPicker.bounds.insetBy(dx: 0, dy: (planetPicker.frame.height - rowHeight) / 2)
            let userTappedOnSelectedRow = selectedRowFrame.contains(tapRecognizer.location(in: planetPicker))
            if userTappedOnSelectedRow {
                let selectedRow = planetPicker.selectedRow(inComponent: 0)
                upgradePlanetName = skyBalls[selectedRow].getName()
                let settings = UIStoryboard(name: "PlanetUpgrade", bundle: .main).instantiateViewController(withIdentifier: "Upgrade") as! UpgradeViewController
                self.present(settings, animated: false)
            }
        }
    }

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }

I do reload the UIPickerView upon a button press that increases the size of the skyBalls array:

planetPicker.reloadAllComponents()

BUT the problem still occurs if planetPicker.reloadAllComponents() is entirely removed in all forms from the project.

I have tried restating my mac, iphone, and xcode, as well as deleting derived data. I cleaned the build folder and nothing seems to fix the issue.

Thank you in advance.


Solution

  • Ok so I found out that it wasn't the UIpickerView's fault at all. So after looking around I tried this:

    1) Open "Breakpoint navigator"

    2) tap '+' button and choose the "Exception Breakpoint" option

    it then took me to the root of the problem witch was an array index out of bounds that for some reason wasn't crashing the app.