问题
The following code should show two ways to pass information from an embedded controller (UICollectionView) back to a detailed view controller using either the Responder Chain OR delegate approach. Both approaches use the same protocol, and delegate method. The only difference is if I comment out the delegate?.method line in didSelectItemAtIndex path, the Responder Chain works. BUT, if I comment out the Responder Chain line in the didSelectItemAtIndex method, the uncommentented delegate? property doesn't call the method, and remains nil.
Protocol defined and included above DetailViewController. Needed for both approaches.
protocol FeatureImageController: class {
func featureImageSelected(indexPath: NSIndexPath)
}
Delegate property declared in the custom UICollectionViewController class, which is only needed for delegate approach.
class PhotoCollectionVC: UICollectionViewController
{
weak var delegate: FeatureImageController?
In DetailViewController, an instance of PhotoCollectionVC() is created, and the delegate property set to self with the delegate protocol as type.
class DetailViewController: UIViewController, FeatureImageController
{...
override func viewDidLoad() {
super.viewDidLoad()
let photoCollectionVC = PhotoCollectionVC()
photoCollectionVC.delegate = self as FeatureImageController
Within the collection view controller's didSelectItemAtIndexPath method, pass back the selected indexPath via either the Responder Chain (commented out) OR the delegate to the featureImageSelected method in the DetailVC.
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
// if let imageSelector = targetForAction("featureImageSelected:", withSender: self) as? FeatureImageController {
// imageSelector.featureImageSelected(indexPath)
// }
self.delegate?.featureImageSelected(indexPath)
}
An instance of elegate method in DetailViewController. Needed for both.
func featureImageSelected(indexPath: NSIndexPath) {
record?.featureImage = record?.images[indexPath.row]
self.configureView()
}
Why would the Responder Chain approach work, but the delegate not?
There are no compiler or run time errors. Within the didSelectItemAtIndexPath method, the delegate always returns nil and nothing prints from the delegate method.
回答1:
Your responder code calls a featureImageSelected on self:
self.featureImageSelected(indexPath)
but the delegate code calls featureImageSelected on the delegate:
self.delegate.featureImageSelected(indexPath)
Which would be the DetailVC's delegate, not the collectionViews delegate. Im not really sure what your code is doing, but you probably want something like
collectionView.delegate?.featureImageSelected(IndexPath)
which looks like it would just end up being
self.featureImageSelected(indexPath)
回答2:
The error in the question is where, in the conforming class, "an instance of PhotoCollectionVC() is created, and the delegate property set to self". In viewDidLoad, that just creates another instance with an irrelevant delegate property that will never be called. The delegate property of the actual embedded PhotoCollectionVC needs to be assigned to self - in order for the two VCs to communicate. This is done from within the prepareForSegue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
...
let controller = (segue.destinationViewController as! PhotoCollectionVC)
...
controller.delegate = self
}
}
}
The rest of the example code is fine.
Here is a super simple example of delegation from an embedded container to its delegate VC. The embedded container simply tells the VC that a button has been pressed. The story board is just a VC with a container in it and a text outlet. In the container VC, there is just a button. And the segue has an identifier.
The code in the delegate ViewController is:
protocol ChangeLabelText: class
{
func changeText()
}
class ViewController: UIViewController, ChangeLabelText
{
@IBOutlet weak var myLabel: UILabel!
override func viewDidLoad()
{
super.viewDidLoad()
myLabel?.text = "Start"
}
func changeText()
{
myLabel?.text = "End"
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "feelTheBern"
{
let secondVC: myViewController = segue.destinationViewController as! myViewController
secondVC.delegate = self
}}
}
The code in the delegating View Controller, myViewController, is:
class myViewController: UIViewController
{
weak var delegate: ChangeLabelText?
@IBAction func myButton(sender: AnyObject)
{
print("action")
delegate?.changeText()
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
来源:https://stackoverflow.com/questions/34138931/responder-chain-but-not-delegate-property-passes-value-back-to-view-controller-f