I cannot seem to find the connection to have an external class manage a view in a ViewController. I'm new to iOS and have spent considerable looking for a solution. Simple Example:
Subclass of UIPickerView
I create a file that is a subclass of UIPickerView and have it conform to the PickerView delegate and datasource.
class MyPickerView: UIPickerView, UIPickerViewDelegate, UIPickerViewDataSource {
//In here I conform to all the required methods...no problems there
}
Main View Controller with Outlet for the PickerView
In my MainViewController, I create an outlet for my picker view. Also, in the StoryBoard I hookup the "custom class" for my Picker View to MyPickerView above.
class MainViewController: UIViewController {
@IBOutlet weak var myPickerView: UIPickerView!
override func viewDidLoad() {
//how do I hookup my picker view class
}
}
My Questions:
How do I tell my MainViewController that my subclass "MyPickerView" is managing the picker view for it?
How did I enable communication between the subclass and the view controller?
---------------------
UPDATE: FINAL SOLUTION Incorporating @Oscar's Answer
@Oscar's suggestion below was great. To clarify, I wanted my PickerView subclass to be the UIPickerView Delegate because the Picker will always have the same UI and there are many PickerView delegate methods for UI. (attributedTitleForRow, widthForComponent, rowHeightForComponent, etc) I don't want to call those delegate methods in every ViewController that uses this PickerView.
Now, when the PickerView "didSelectRow" is called, we need to notify our ViewController and pass the value that was selected. To get this to work, I used a Protocol. (summarized below) This topic took me a while to learn, but is crucial, so I suggest spending time with Protocols & Delegation if this doesn't make sense.
Create a protocol in the PickerView with a func that will be used to talk to ViewControllers that present this PickerView:
protocol MyPickerViewProtocol { func myPickerDidSelectRow(selectedRowValue:Int?) }
In the ViewController presenting the PickerView, conform to your PickerView protocol. By doing so, you will have to place the func myPickerDidSelectRow somewhere in your ViewController:
class MyViewController: MyPickerViewProtocol { func myPickerDidSelectRow(selectedRowValue:Int?) { //do stuff to update your ViewController } }
@Oscar's answer below will hookup the picker view to your view controller, but there's one last thing. In order for the PickerView to talk back, you will want a property in your PickerView, that is a reference to the view controller it's contained in. Here's the PickeView and ViewController classes in perspective:
//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
Now when a row is selected in our PickerView, let's tell the ViewController using our property: propertyThatReferencesThisViewController
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 } }
I think you may have got hold of the wrong end of the stick!
Why do you want to make the picker its own delegate? The point of having a delegate is that it can tell its delegate what has been selected etc.
I would think that what you should be doing is making your view controller conform to
UIPickerViewDelegate
and make it the delegate of the picker and put the logic for whatever you want to happen when an item is picked in those delegate methods. I can't see any other way of 'telling' your view controller about the picker.Also, if you reference to your picker is
weak
, then unless you are holding astrong
reference to it somewhere else, at all times (eg it is part of the view hierarchy) it will be deallocated.Subclass Pickerview
Main View Controller with Outlet for the PickerView