2017-03-11 64 views
2

我有一个在UIViewController中实例化的子UIView类,UIViewController有一个名为sigIn(){}的函数。我需要从UIView中调用这个函数。Swift3在子视图中父函数调用函数

我试着以某种方式使用self.superview并将其转换成一个UIViewController,但这不起作用。我发现了一种方法,您使用侦听器来检测触发器,但我认为这不是一个好的解决方案。有没有一种简单的方式来访问paren视图中子视图的功能?

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

    ("Call parent signIn() function") 

    } 

    (init etc. ...) 
} 
+0

请发布调用'signIn()'的UIView函数的代码?通常你使用委托或目标行动模式,所以你不需要关心谁是你的父母。 – kennytm

+0

我看到一个代表解决方案,但它在C中,我不明白它是如何工作的。 – Luis

+0

所以你想从你的UIViewController调用UIView方法吗? –

回答

6

首先,View and a View Controller are two different concepts.superview将不会给你一个视图控制器,并铸造它只会使程序崩溃。

虽然it is possible to find out the current View Controller,但在您的用例中它是非常单一的,因为您无法确定View Controller是否具有signIn()函数,甚至无法确保“当前视图控制器”是视图的视图控制器。


iOS通常使用"delegate pattern"代替。在你的情况,必须首先定义一个协议signIn()功能:

protocol SignInDelegate { 
    func signIn() 
} 

然后,查看需要提供该协议的一个变量。这个变量被称为代表。无论何时我们想登录,只需拨打代表的signIn()函数即可。

该变量应该是对avoid strong reference cycle的弱引用。该协议也needs to be class-bound,否则编译器会抱怨。

​​

接下来我们适应了协议的视图控制器:

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

我们通常暴露这个委托界面生成器,所以我们可以查看简单地连接到视图控制器分配委托。

enter image description here

这是通过adding @IBOutlet做委托场。不幸的是,Xcode only recognizes AnyObject/NSObject for 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. 
} 
+0

非常感谢你的解释,完美的工作XD – Luis

+0

我会说“接下来,我们让ViewController采用(或遵循)协议”,而不是“接下来我们适应视图控制器协议:“,但它是一个细节 –

0

声明signIn()函数的协议,并让父ViewController符合该协议。然后,让父视图控制器的SignUIView委托:

protocol SignInProtocol { 
    func signIn() 
} 

class MyViewController: UIViewController, SignInProtocol { 
    var signUIView: SignUIView 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     self.signUIView = SignUIView() 
     self.signUIView.delegate = self // set the delegate 
    } 


    func signIn() { 
     ... 
    } 
} 


class SignUIView: UIView { 
    var delegate: SignProtocol? // the delegate 

    func signInUIButtonH(sender: UIButton) { 
    // call the delegate 
    self.delegate?.signIn() 
    } 

    (init etc. ...) 
} 
+0

你有什么“设置委托”它会抛出错误,“不能分配值类型”MyViewController'键入'SignInProtocol?'“ – Luis

+0

您需要设置SignInProtocol声明在ViewController上:'class MyViewController:UIViewController,SignInProtocol' – zisoft