I have a UIViewController and a UIView inside it. When I try to add an alert inside the UIView, I have to use the controller to present the UIAlertController. How do I pass the reference of UIViewController to the UIView class? Or alternatively how do I create a delegate of controller?
class GameViewController: UIViewController {
@IBOutlet var gameBoardUIView: GameBoardUIView
...
}
class GameBoardUIView: UIView {
...
func move() {
if !gameBoard.checkNextMoveExist() {
var alert = UIAlertController(title: "Game Over", message: nil, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Cancel, handler: {(action: UIAlertAction!) in
println("Game Over")
}))
}))
// Following would fail because self is not a UIViewController here
// self.presentViewController(alert, animated: true, completion: nil)
}
}
}
Following the MVC pattern, a ViewController knows about its Views, but the View shouldn't know about the ViewController. Instead you should declare delegate protocol for GameBoardUIView
that your ViewController
adopts as follows:
// Delegate protocol declared here
protocol GameBoardUIViewDelegate: class {
func checkIfNextMoveExistsForGameBoardUIView(gameBoardUIView: GameBoardUIView)
}
class GameBoardUIView: UIView {
// GameBoardUIView has a delegate property that conforms to the protocol
// weak to prevent retain cycles
weak var delegate:GameBoardUIViewDelegate?
func move() {
if !gameBoard.checkNextMoveExist() {
delegate?.checkIfNextMoveExistsForGameBoardUIView(gameBoardUIView: self)
}
}
}
// View controller subclass adopts the protocol
class GameViewController: UIViewController, GameBoardUIViewDelegate {
@IBOutlet var gameBoardUIView: GameBoardUIView!
override func viewDidLoad() {
super.viewDidLoad()
gameBoardUIView.delegate = self
}
// Delegte protocol method
func checkIfNextMoveExistsForGameBoardUIView(gameBoardUIView: GameBoardUIView) {
let alert = UIAlertController(title: "Game Over", message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: {(action: UIAlertAction!) in
print("Game Over")
}))
// If you need to feed back to the game view you can do it in the completion block here
present(alert, animated: true, completion: nil)
}
}
alternatively, you can also post notifications from your .xib and have the parent viewcontroller observes it. you will be able to send data via userInfo object during the posting.