Swift - How to pass a view controller's refere

2019-02-06 22:06发布

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)
        }
    }
}

2条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-02-06 22:39

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)
    }
}
查看更多
Fickle 薄情
3楼-- · 2019-02-06 22:45

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.

查看更多
登录 后发表回答