子视图中的函数中的Swift3调用函数

Mer*_*ury 2 parent-child superview swift swift3

我在UIViewController中实例化了一个子UIView类,UIViewController有一个名为sigIn(){}的函数.我需要在UIView中调用这个函数.

我尝试使用self.superview并将其转换为UIViewController,但这不起作用.我发现了一种使用侦听器来检测触发器的方法,但我认为这不是一个好的解决方案.在子视图的paren视图中是否有另一种简单的方法来访问函数?

class SignUIView: UIView {
  func signInUIButtonH(sender: UIButton) {

    ("Call parent signIn() function")

  }

  (init etc. ...)
}
Run Code Online (Sandbox Code Playgroud)

ken*_*ytm 9

首先,View和View Controller是两个不同的概念..superview不会给你一个视图控制器,并且它只会使程序崩溃.

虽然可以找到当前的View Controller,但它在您的使用案例中非常简单,因为您无法确定View Controller是否具有该signIn()功能,您甚至无法确保"当前View Controller"是View Controller的视图控制器.风景.


iOS通常使用"委托模式".在你的情况,必须首先定义一个协议signIn()功能:

protocol SignInDelegate {
    func signIn()
}
Run Code Online (Sandbox Code Playgroud)

然后,View需要提供此协议的变量.此变量称为委托.每当我们想要登录时,只需调用委托的signIn()功能即可.

变量应该是弱参考,以避免强引用周期.协议也需要是类绑定的,否则编译器会抱怨.

protocol SignInDelegate: class {    // <-- needs :class for weak
    func signIn()
}

class SignUIView: UIView {
    weak var delegate: SignInDelegate?    // <-- delegate

    func signInUIButtonH(sender: UIButton) {
        delegate?.signIn()    // <-- call the delegate
    }
}
Run Code Online (Sandbox Code Playgroud)

接下来,我们将协议调整为View Controller:

class SignInViewController: UIViewController, SignInDelegate {   // <-- adapt the protocol
    func signIn() {    // <-- implement the function
        print("sign in")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        signInView.delegate = self    // <-- tell the subview we will be the delegate.
    }
}
Run Code Online (Sandbox Code Playgroud)

我们通常会将此委托公开给Interface Builder,因此我们只需将View连接到View Controller即可分配委托.

在此输入图像描述

这是通过添加@IBOutlet到委托字段来完成的.不幸的是,Xcode只识别AnyObject/ NSObject用于IBOutlet,这违背了使用委托模式进行类型安全的整个目的.所以我们需要引入一些丑陋的黑客来为IB解决它.该协议现在也需要,@objc因为解析这些IB连接需要Objective-C运行时.

@objc protocol SignInDelegate {   // <-- needs @objc for IB (:class is implied by @objc)
    func signIn()
}

class SignUIView {
    // Blame Xcode for this mess. See https://stackoverflow.com/a/42227800/224671
    #if TARGET_INTERFACE_BUILDER
    @IBOutlet weak var delegate: AnyObject?
    #else
    weak var delegate: SignInDelegate?
    #endif

    func signInUIButtonH(sender: UIButton) {
        delegate?.signIn()
    }
}

class SignInViewController: UIViewController, SignInDelegate {   // <-- adapt the protocol
    func signIn() {    // <-- implement the function
        print("sign in")
    }
    // Note: no need to set signInView.delegate manually.
}
Run Code Online (Sandbox Code Playgroud)