从外部管理 UIPickerView Class - 使用 Swift
Manage a UIPickerView from an External Class - Using Swift
我似乎无法找到让外部 class 在 ViewController 中管理视图的连接。我是 iOS 的新手,花了相当多的时间寻找解决方案。简单示例:
UIPickerView
的子class
我创建了一个文件,它是 UIPickerView 的子class,并使其符合 PickerView 委托和数据源。
class MyPickerView: UIPickerView, UIPickerViewDelegate, UIPickerViewDataSource {
//In here I conform to all the required methods...no problems there
}
带 PickerView 出口的主视图控制器
在我的 MainViewController 中,我为我的选择器视图创建了一个出口。此外,在 StoryBoard 中,我将我的 Picker View 的 "custom class" 连接到上面的 MyPickerView 。
class MainViewController: UIViewController {
@IBOutlet weak var myPickerView: UIPickerView!
override func viewDidLoad() {
//how do I hookup my picker view class
}
}
我的问题:
如何告诉我的 MainViewController 我的 subclass "MyPickerView" 正在管理它的选择器视图?
如何启用子class和视图控制器之间的通信?
---------------------
更新:最终解决方案结合@Oscar 的回答
@Oscar 下面的建议很好。澄清一下,我希望我的 PickerView subclass 成为 UIPickerView Delegate,因为 Picker 将始终具有相同的 UI 并且 UI 有许多 PickerView 委托方法。 (attributedTitleForRow、widthForComponent、rowHeightForComponent 等)我不想在每个使用此 PickerView 的 ViewController 中调用这些委托方法。
现在,当 PickerView "didSelectRow" 被调用时,我们需要通知我们 ViewController 并传递选择的值。为了让它工作,我使用了一个协议。 (总结如下)这个主题花了我一段时间来学习,但它很重要,所以如果这没有意义,我建议花时间学习协议和授权。
在 PickerView 中创建一个带有函数的协议,该函数将用于与呈现此 PickerView 的 ViewController 对话:
protocol MyPickerViewProtocol {
func myPickerDidSelectRow(selectedRowValue:Int?)
}
在ViewController中呈现PickerView,符合你的PickerView协议。通过这样做,您必须将 func myPickerDidSelectRow 放在 ViewController:
中的某个位置
class MyViewController: MyPickerViewProtocol {
func myPickerDidSelectRow(selectedRowValue:Int?) {
//do stuff to update your ViewController
}
}
@Oscar 下面的回答会将选择器视图连接到您的视图控制器,但还有最后一件事。为了让 PickerView 回应,您需要在 PickerView 中有一个 属性,这是对包含它的视图控制器的引用。这是 PickeView 和 ViewController classes视角:
//PickerView Subclass ------------------
protocol MyPickerViewProtocol {
func myPickerDidSelectRow(selectedRowValue:Int?)
}
class MyPickerView: UIPickerView {
//Note: this var is of type your Picker protocol above. Because the ViewController will conform to the protocol, this var will be the reference (or the pointer) to the protocol func you implement in your ViewController...which is myPickerDidSelectRow
var propertyThatReferencesThisViewController:MyPickerViewProtocol?
}
//ViewController Class ----------------
myPicker = MyPickerView()
myPickerView.dataSource = myPicker //note: myPickerView is the outlet of type UIPickerView in your ViewController
myPickerView.delegate = myPicker
//HERE'S THE PROPERTY from our PickerView subclass that will point to this ViewController's protocol methods that we implemented. From the MyPickerViewProtocol
myPicker.propertyThatReferencesThisViewController = self
现在,当在我们的 PickerView 中选择一行时,让我们使用我们的 属性 告诉 ViewController:属性ThatReferencesThisViewController
class MyPickerView: UIPickerView {
//This Property points to the ViewController conforming to the protocol. This property will only be able to access the stuff you put in the protocol. It won't access everything in your ViewController
var propertyThatReferencesThisViewController:MyPickerViewProtocol?
//didSelectRow UIPickerView Delegate method that apple gives us
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
//get your picker values that you need
let theRowValue = someArray[row]
propertyThatReferencesThisViewController?.myPickerDidSelectRow(theRowValue)
//the ViewController func will be called passing the row value along
}
}
我想你可能抓错了头!
为什么要让选择器成为它自己的委托?有一个代表的意义在于它可以告诉它的代表已经选择了什么等等。
我认为你应该做的是让你的视图控制器符合 UIPickerViewDelegate
并使其成为选择器的委托,并在选择一个项目时放置你想要发生的任何逻辑那些委托方法。我看不到 'telling' 你的视图控制器关于选择器的任何其他方式。
此外,如果您引用的选择器是 weak
,那么除非您一直在其他地方持有对它的 strong
引用(例如,它是视图层次结构的一部分)它将被释放。
子类 Pickerview
class MyPickerView: UIPickerView, UIPickerViewDataSource, UIPickerViewDelegate {
var oficinas = ["oficina 1", "Oficinas 2", "Oficina 3"]
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return oficinas.count
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return oficinas[row]
}
}
带 PickerView 出口的主视图控制器
class MainViewController: UIViewController {
@IBOutlet weak var myPickerView: UIPickerView!
var pickerOficinas: MyPickerView!
override func viewDidLoad() {
//how do I hookup my picker view class
pickerOficinas = MyPickerView()
myPickerView.delegate = pickerOficinas
myPickerView.dataSource = pickerOficinas
}
}
我似乎无法找到让外部 class 在 ViewController 中管理视图的连接。我是 iOS 的新手,花了相当多的时间寻找解决方案。简单示例:
UIPickerView
的子class我创建了一个文件,它是 UIPickerView 的子class,并使其符合 PickerView 委托和数据源。
class MyPickerView: UIPickerView, UIPickerViewDelegate, UIPickerViewDataSource {
//In here I conform to all the required methods...no problems there
}
带 PickerView 出口的主视图控制器
在我的 MainViewController 中,我为我的选择器视图创建了一个出口。此外,在 StoryBoard 中,我将我的 Picker View 的 "custom class" 连接到上面的 MyPickerView 。
class MainViewController: UIViewController {
@IBOutlet weak var myPickerView: UIPickerView!
override func viewDidLoad() {
//how do I hookup my picker view class
}
}
我的问题:
如何告诉我的 MainViewController 我的 subclass "MyPickerView" 正在管理它的选择器视图?
如何启用子class和视图控制器之间的通信?
---------------------
更新:最终解决方案结合@Oscar 的回答
@Oscar 下面的建议很好。澄清一下,我希望我的 PickerView subclass 成为 UIPickerView Delegate,因为 Picker 将始终具有相同的 UI 并且 UI 有许多 PickerView 委托方法。 (attributedTitleForRow、widthForComponent、rowHeightForComponent 等)我不想在每个使用此 PickerView 的 ViewController 中调用这些委托方法。
现在,当 PickerView "didSelectRow" 被调用时,我们需要通知我们 ViewController 并传递选择的值。为了让它工作,我使用了一个协议。 (总结如下)这个主题花了我一段时间来学习,但它很重要,所以如果这没有意义,我建议花时间学习协议和授权。
在 PickerView 中创建一个带有函数的协议,该函数将用于与呈现此 PickerView 的 ViewController 对话:
protocol MyPickerViewProtocol { func myPickerDidSelectRow(selectedRowValue:Int?) }
在ViewController中呈现PickerView,符合你的PickerView协议。通过这样做,您必须将 func myPickerDidSelectRow 放在 ViewController:
中的某个位置class MyViewController: MyPickerViewProtocol { func myPickerDidSelectRow(selectedRowValue:Int?) { //do stuff to update your ViewController } }
@Oscar 下面的回答会将选择器视图连接到您的视图控制器,但还有最后一件事。为了让 PickerView 回应,您需要在 PickerView 中有一个 属性,这是对包含它的视图控制器的引用。这是 PickeView 和 ViewController classes视角:
//PickerView Subclass ------------------ protocol MyPickerViewProtocol { func myPickerDidSelectRow(selectedRowValue:Int?) } class MyPickerView: UIPickerView { //Note: this var is of type your Picker protocol above. Because the ViewController will conform to the protocol, this var will be the reference (or the pointer) to the protocol func you implement in your ViewController...which is myPickerDidSelectRow var propertyThatReferencesThisViewController:MyPickerViewProtocol? } //ViewController Class ---------------- myPicker = MyPickerView() myPickerView.dataSource = myPicker //note: myPickerView is the outlet of type UIPickerView in your ViewController myPickerView.delegate = myPicker //HERE'S THE PROPERTY from our PickerView subclass that will point to this ViewController's protocol methods that we implemented. From the MyPickerViewProtocol myPicker.propertyThatReferencesThisViewController = self
现在,当在我们的 PickerView 中选择一行时,让我们使用我们的 属性 告诉 ViewController:属性ThatReferencesThisViewController
class MyPickerView: UIPickerView { //This Property points to the ViewController conforming to the protocol. This property will only be able to access the stuff you put in the protocol. It won't access everything in your ViewController var propertyThatReferencesThisViewController:MyPickerViewProtocol? //didSelectRow UIPickerView Delegate method that apple gives us func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { //get your picker values that you need let theRowValue = someArray[row] propertyThatReferencesThisViewController?.myPickerDidSelectRow(theRowValue) //the ViewController func will be called passing the row value along } }
我想你可能抓错了头!
为什么要让选择器成为它自己的委托?有一个代表的意义在于它可以告诉它的代表已经选择了什么等等。
我认为你应该做的是让你的视图控制器符合 UIPickerViewDelegate
并使其成为选择器的委托,并在选择一个项目时放置你想要发生的任何逻辑那些委托方法。我看不到 'telling' 你的视图控制器关于选择器的任何其他方式。
此外,如果您引用的选择器是 weak
,那么除非您一直在其他地方持有对它的 strong
引用(例如,它是视图层次结构的一部分)它将被释放。
子类 Pickerview
class MyPickerView: UIPickerView, UIPickerViewDataSource, UIPickerViewDelegate {
var oficinas = ["oficina 1", "Oficinas 2", "Oficina 3"]
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return oficinas.count
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return oficinas[row]
}
}
带 PickerView 出口的主视图控制器
class MainViewController: UIViewController {
@IBOutlet weak var myPickerView: UIPickerView!
var pickerOficinas: MyPickerView!
override func viewDidLoad() {
//how do I hookup my picker view class
pickerOficinas = MyPickerView()
myPickerView.delegate = pickerOficinas
myPickerView.dataSource = pickerOficinas
}
}