UIPickerView 在重新加载时冻结 UI
UIPickerView freezes UI when reloaded
当 UIPickerView 的索引为 1 或元素数量为 2 时,我的应用程序的 ui 冻结。我真的很困惑,因为它正在运行,然后突然坏了。我做了一些研究,发现它可能与线程有关。有人可以帮我解决 UIPickerView 的问题吗?
// class implements UIPickerViewDelegate, UIPickerViewDataSource, UIGestureRecognizerDelegate
@IBOutlet weak var planetPickerView: UIView!
var planetPicker: UIPickerView!
视图已加载:
override func viewDidLoad() {
super.viewDidLoad()
//Other code not important
configurePlanetPicker()
}
UIPickerView 实现:(skyBalls 是 类 的数组,其中包含各种数据作为 getter)
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
}
我确实在按下增加 skyBalls 数组大小的按钮时重新加载 UIPickerView:
planetPicker.reloadAllComponents()
但是如果 planetPicker.reloadAllComponents()
以所有形式从项目中完全删除,问题仍然存在。
我已尝试重述我的 mac、iphone 和 xcode,以及删除派生数据。我清理了 build 文件夹,但似乎无法解决问题。
提前致谢。
当你必须更新你的观点时
您必须始终在主线程上调用 .reloadAllComponents()
DispatchQueue.main.async
才能解决问题。
DispatchQueue.main.async {
self.planetPickerView.reloadAllComponents()
}
好的,所以我发现这根本不是 UIpickerView 的错。
所以环顾四周后,我尝试了这个:
1) Open "Breakpoint navigator"
2) tap '+' button and choose the "Exception Breakpoint" option
然后我找到了问题的根源 是数组索引越界,由于某种原因没有使应用程序崩溃。
当 UIPickerView 的索引为 1 或元素数量为 2 时,我的应用程序的 ui 冻结。我真的很困惑,因为它正在运行,然后突然坏了。我做了一些研究,发现它可能与线程有关。有人可以帮我解决 UIPickerView 的问题吗?
// class implements UIPickerViewDelegate, UIPickerViewDataSource, UIGestureRecognizerDelegate
@IBOutlet weak var planetPickerView: UIView!
var planetPicker: UIPickerView!
视图已加载:
override func viewDidLoad() {
super.viewDidLoad()
//Other code not important
configurePlanetPicker()
}
UIPickerView 实现:(skyBalls 是 类 的数组,其中包含各种数据作为 getter)
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
}
我确实在按下增加 skyBalls 数组大小的按钮时重新加载 UIPickerView:
planetPicker.reloadAllComponents()
但是如果 planetPicker.reloadAllComponents()
以所有形式从项目中完全删除,问题仍然存在。
我已尝试重述我的 mac、iphone 和 xcode,以及删除派生数据。我清理了 build 文件夹,但似乎无法解决问题。
提前致谢。
当你必须更新你的观点时
您必须始终在主线程上调用 .reloadAllComponents()
DispatchQueue.main.async
才能解决问题。
DispatchQueue.main.async {
self.planetPickerView.reloadAllComponents()
}
好的,所以我发现这根本不是 UIpickerView 的错。 所以环顾四周后,我尝试了这个:
1) Open "Breakpoint navigator"
2) tap '+' button and choose the "Exception Breakpoint" option
然后我找到了问题的根源 是数组索引越界,由于某种原因没有使应用程序崩溃。