【问题标题】:Swift - How to pass a view controller's reference to a sub UIView class?Swift - 如何将视图控制器的引用传递给子 UIView 类?
【发布时间】:2014-07-06 09:00:51
【问题描述】:

我里面有一个 UIViewController 和一个 UIView。当我尝试在 UIView 中添加警报时,我必须使用控制器来呈现 UIAlertController。如何将 UIViewController 的引用传递给 UIView 类?或者如何创建控制器的委托?

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

【问题讨论】:

标签: ios uiview uiviewcontroller swift


【解决方案1】:

按照 MVC 模式,ViewController 知道它的 View,但 View 不应该知道 ViewController。相反,您应该为您的ViewController 采用的GameBoardUIView 声明委托协议,如下所示:

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

【讨论】:

  • 感谢您的链接。关于您的代码,我有两个问题。首先是我们在哪里分配委托值?默认情况下它是 nil ,对吗?第二个问题是,我注意到您将@IBOutlet var gameBoardUIView: GameBoardUIView 替换为let gameView = GameBoardUIView() ,这是如何工作的?
  • 现在说得通了。除了弱引用不起作用。我将在self.delegate?.checkIfNextMoveExistsForGameBoardUIView(gameBoardUIView: self) 收到 EXC_BAD_ACCESS 异常。如果我使用普通参考,它可以成功弹出警报。
  • 谢谢你,对一个视图控制器工作得很好,但是有没有办法让它在多个视图控制器中工作而不重复代码?使用 AppDelegate?还是 UIViewController 的扩展?
【解决方案2】:

或者,您也可以从 .xib 发布通知并让父视图控制器观察它。您将能够在发布期间通过 userInfo 对象发送数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-12
    • 2015-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-14
    • 2018-12-23
    相关资源
    最近更新 更多