Swift3 在​​ subview 中的父函数外调用函数

标签 swift swift3 parent-child superview

我有一个在 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)。

enter image description here

这是由 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/

相关文章:

swift - 知道用户是否更新应用程序或是否有新购买(swift 3)

PHP 对象到 JSON : How to create class that will have multiple recursive children?

ios - 在 Storyboard 中查看数组 MxN 的方法 - Swift 3- Xcode 8.2.1

arrays - UICollectionView 没有显示我的所有数组

ios - 将信息从 TableView 传递到 View Controller 不是基于 indexPathForSelectedRow,而是基于所选单元格的标签文本?

c++ - 使用c++在windows中进行两种方式的父子通信

Python:使用字符串调用子函数

ios - Swift:发布版本中 assertionFailure 的奇怪行为

ios - Swift:如何在加载 View Controller X 次后创建事件

swift - 如何呈现类似于 MFMailComposeViewController 的 UIViewController