我有一个在 UIViewController 中实例化的子 UIView 类,UIViewController 有一个名为 sigIn(){} 的函数。我需要从 UIView 中调用此函数。
我尝试以某种方式使用 self.superview 并将其转换为 UIViewController 但这没有用。我找到了一种使用监听器检测触发器的方法,但我认为这不是一个好的解决方案。是否有另一种简单的方法可以从 subview 访问父 View 中的函数?
class SignUIView: UIView {
func signInUIButtonH(sender: UIButton) {
("Call parent signIn() function")
}
(init etc. ...)
}
最佳答案
首先,View and a View Controller are two different concepts。 .superview
不会给你一个 View Controller,转换它只会让程序崩溃。
虽然 it is possible to find out the current View Controller ,但它在您的用例中非常不合常理,因为您无法确定 View Controller 是否具有 signIn()
功能,您甚至无法确保“当前 View Controller”是 View 的 View Controller 。
iOS 通常使用 "delegate pattern" 代替。在您的情况下,首先您为 signIn()
函数定义一个 protocol:
protocol SignInDelegate {
func signIn()
}
然后,View需要提供一个这个协议(protocol)的变量。此变量称为委托(delegate)。每当我们想要登录时,只需调用委托(delegate)的 signIn()
函数即可。
该变量应该是对 avoid strong reference cycle 的弱引用。该协议(protocol)也是 needs to be class-bound ,否则编译器会报错。
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
}
}
接下来我们调整协议(protocol)以适应 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.
}
}
我们通常将此委托(delegate)公开给 Interface Builder,这样我们就可以简单地将 View 连接到 View Controller 来分配委托(delegate)。
这是由 adding @IBOutlet
对委托(delegate)字段完成的。不幸的是,Xcode only recognizes AnyObject
/NSObject
for IBOutlet 违背了使用委托(delegate)模式实现类型安全的全部目的。所以我们需要引入一些丑陋的 hack 来为 IB 解决它。该协议(protocol)现在还需要 @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.
}
关于Swift3 在 subview 中的父函数外调用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42732168/