событие отправки родительскому ViewController в swift
Я исхожу из as AS3 фона, поэтому мне может быть проще показать вам, что я пытаюсь сделать с AS3. У меня есть UIViewController(root), и внутри у меня есть ContainerView. У меня сложилось впечатление, что UIViewController представления контейнера является дочерним элементом UIViewController(root). Я хотел бы, чтобы кнопка была нажата на контроллере дочернего представления (контейнерный вид) и пузырь этого события до родительского(root UIViewController). В AS3 у меня было бы что-то вроде это
корневой класс создает дочерний класс
var childClass = new ChildClass()
childClass.addEventListener("buttonWasPressed", callThisFunction);
private function callThisFunciton(e:Event):void
{
// move the child view
TweenLite.to(childClass,1,{x:100});
}
и в дочернем классе у меня есть функция кнопки, которая развернет это событие, которое будет пузыриться до родителя.
dispatchEvent(new Event("buttonWasPressed", true));
что я не уверен, как сделать, это заставить корневой VC слушать это событие. Поскольку я использую containerView, я не уверен, как настроить выход для этого дочернего VC и слушать то, что делает ребенок. Я могу управлять перетаскиванием из IB в VC, но это только что создало выход для UIView, представляющего представление контейнера. Когда я печатаю некоторый текст, я вижу, что контроллер дочернего представления создается сначала перед родительским VC.
Я нашел этот пост, что я думаю, указывает в правильном направлении. https://craiggrummitt.wordpress.com/2014/07/14/communication-between-objects-in-objective-c-and-swift-compared-with-actionscript-part-5/
но я получаю ошибку, скорее всего, потому, что я не уверен, как сделайте соединение от родительского VC к дочернему VC, который находится внутри представления контейнера. Я огляделся, и я не могу найти много информации по этой теме.
Спасибо за помощь!
2 ответов
есть два пути:
1) Используйте протокол делегата (рекомендуется)
a) в вашем ребенке создайте протокол делегата и необязательное свойство на дочернем VC, которое будет содержать делегат.
protocol ChildViewControllerDelegate {
}
class ChildViewController: UIViewController {
var delegate:ChildViewControllerDelegate?
}
b) в протоколе делегата создайте метод, который будет вызываться при нажатии кнопки, и реализуйте buttonWasPressed()
метод в дочернем элементе, который вызывает этот метод на делегате. (Вы захотите подключить этот метод к a кнопка в раскадровке)
protocol ChildViewControllerDelegate {
func childViewControllerDidPressButton(childViewController:ChildViewController)
}
class ChildViewController: UIViewController {
var delegate:ChildViewControllerDelegate?
@IBOutlet weak var button: UIButton!
@IBAction func buttonWasPressed(sender: AnyObject) {
self.delegate?.childViewControllerDidPressButton(self)
}
}
c) Сделайте ваш родительский контроллер представления соответствующим дочернему протоколу
class ParentViewController: UIViewController, ChildViewControllerDelegate {
func childViewControllerDidPressButton(childViewController: ChildViewController) {
// Do fun handling of child button presses!
}
}
c) Когда дочерний элемент встроен в родительский, запускается специальный вид segue, называемый embed segue. Вы можете увидеть его в раскадровке - это линия, которая соединяет ребенка к родителю:
добавьте идентификатор к этому сегменту в раскадровке:
и постоянном для него в контроллере родительского вида:
struct Constants {
static let embedSegue = "embedSegue"
}
class ParentViewController: UIViewController, ChildViewControllerDelegate {
func childViewControllerDidPressButton(childViewController: ChildViewController) {
// Do fun handling of child button presses!
}
}
d) затем в контроллере родительского вида переопределите prepareForSegue()
метод и проверить, если segue.identifier
соответствует тому, что вы установите в качестве идентификатора. Если это так, то вы можете получить ссылку на контроллер дочернего представления через segue.destinationViewController
. Приведите это в качестве контроллера дочернего представления, затем вы можете установить родительский делегат:
struct Constants {
static let embedSegue = "embedSegue"
}
class ParentViewController: UIViewController, ChildViewControllerDelegate {
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == Constants.embedSegue {
let childViewController = segue.destinationViewController as ChildViewController
childViewController.delegate = self
}
}
func childViewControllerDidPressButton(childViewController: ChildViewController) {
// Do fun handling of child button presses!
}
}
e) выиграть!
2) Используйте NSNotification и NSNotificationCenter
вы можете думать об этом как о событиях ActionScript, однако они не всплывают автоматически через иерархию представлений, как AS. Вместо этого уведомления отправляются глобально через NSNotificationCenter
. Я предпочитаю использовать это только тогда, когда есть несколько объектов, которые должны прослушивать одно конкретное событие.
вы можете найти более подробную информацию о NSNotification
и NSNotificationCenter
здесь: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/
ну или вы можете использовать статические переменные, что, вероятно, является самым простым способом.
class ParentViewController: UIViewController {
static var instance:ParentViewController?
override func awakeFromNib() {
self.dynamicType.instance = self
}
func parentFunction() {
print("called \(#function) in \(self.dynamicType)")
}
}
class ChildViewController: UIViewController {
func childFunction() {
ParentViewController.instance?.parentFunction()
}
override func viewDidAppear(_ animated: Bool) {
childFunction()
}
}