Цепочка ответчика, но НЕ делегирующее свойство передает значение обратно в контроллер просмотра из контейнера
В следующем коде должны быть показаны два способа передачи информации из встроенного контроллера (UICollectionView) обратно в контроллер подробного представления с использованием подхода цепочки ответчика ИЛИ делегата. Оба подхода используют один и тот же протокол и метод делегата. Единственное отличие состоит в том, что если я закомментирую строку делегата?.method в пути didSelectItemAtIndex, цепочка респондента будет работать. НО, если я закомментирую строку цепочки респондента в методе didSelectItemAtIndex, то незарегистрированный делегат? Свойство не вызывает метод и остается нулевым.
Протокол определен и включен выше DetailViewController. Необходим для обоих подходов.
protocol FeatureImageController: class {
func featureImageSelected(indexPath: NSIndexPath)
}
Свойство делегата, объявленное в пользовательском классе UICollectionViewController, которое необходимо только для подхода делегата.
class PhotoCollectionVC: UICollectionViewController
{
weak var delegate: FeatureImageController?
В DetailViewController создается экземпляр PhotoCollectionVC(), а для свойства делегата устанавливается значение self с протоколом делегата в качестве типа.
class DetailViewController: UIViewController, FeatureImageController
{...
override func viewDidLoad() {
super.viewDidLoad()
let photoCollectionVC = PhotoCollectionVC()
photoCollectionVC.delegate = self as FeatureImageController
В методе didSelectItemAtIndexPath контроллера представления коллекции передайте обратно выбранный indexPath через цепочку респондента (закомментировано) ИЛИ делегат методу featureImageSelected в 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)
}
Экземпляр элегантного метода в DetailViewController. Необходим для обоих.
func featureImageSelected(indexPath: NSIndexPath) {
record?.featureImage = record?.images[indexPath.row]
self.configureView()
}
Почему подход цепочки ответчика работает, а делегат - нет?
Нет ошибок компилятора или времени выполнения. В методе didSelectItemAtIndexPath делегат всегда возвращает nil, и из метода делегата ничего не печатается.
2 ответа
Ошибка в вопросе заключается в том, где в соответствующем классе "создается экземпляр PhotoCollectionVC(), а для свойства делегата устанавливается значение self". В viewDidLoad это просто создает другой экземпляр с нерелевантным свойством делегата, которое никогда не будет вызываться. Свойство делегата фактического встроенного PhotoCollectionVC должно быть присвоено self - для того, чтобы два VC могли обмениваться данными. Это делается из метода prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
...
let controller = (segue.destinationViewController as! PhotoCollectionVC)
...
controller.delegate = self
}
}
}
Остальной пример кода в порядке.
Вот очень простой пример делегирования из встроенного контейнера в его делегированный VC. Встроенный контейнер просто сообщает ВК, что кнопка была нажата. Доска объявлений - это просто ВК с контейнером и текстовым выпуском. В контейнере ВК есть только кнопка. И у segue есть идентификатор.
Код в делегате ViewController:
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
}}
}
Код в делегирующем контроллере представления myViewController:
class myViewController: UIViewController
{
weak var delegate: ChangeLabelText?
@IBAction func myButton(sender: AnyObject)
{
print("action")
delegate?.changeText()
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Ваш код респондента вызывает функцию FeatureImageSelected для себя:
self.featureImageSelected(indexPath)
но код делегата вызывает функцию featureImageSelected для делегата:
self.delegate.featureImageSelected(indexPath)
Который будет делегатом DetailVC, а не делегатом collectionViews. Я не совсем уверен, что делает ваш код, но вы, вероятно, хотите что-то вроде
collectionView.delegate?.featureImageSelected(IndexPath)
который выглядит так, как будто бы
self.featureImageSelected(indexPath)