2017-03-11 5 views
2

Ich habe eine untergeordnete UIView-Klasse in einem UIViewController instanziiert, der UIViewController hat eine Funktion namens sigIn() {}. Ich muss diese Funktion aus UIView aufrufen.Swift3 Call-Funktion in übergeordnete Funktion in untergeordneten Ansicht

Ich versuchte irgendwie die self.superview zu verwenden und es in einen UIViewController zu werfen, aber das hat nicht funktioniert. Ich habe eine Methode gefunden, bei der Sie einen Listener verwenden, um den Trigger zu erkennen, aber ich denke, das ist keine gute Lösung. Gibt es eine einfache Möglichkeit, auf Funktionen in der paren-Ansicht der Unteransicht zuzugreifen?

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

    ("Call parent signIn() function") 

    } 

    (init etc. ...) 
} 
+0

Bitte den Code der Funktion der UIView, die 'signIn() 'aufruft, eingeben? Normalerweise verwenden Sie das Delegaten- oder Zielaktionsmuster, sodass Sie sich nicht darum kümmern müssen, wer Ihre Eltern sind. – kennytm

+0

Ich sah eine Delegierte Lösungen, aber es war in C und ich habe nicht verstanden, wie es funktioniert. – Luis

+0

Also möchten Sie UIView-Methode von Ihrem UIViewController Right aufrufen? –

Antwort

6

Erstens View and a View Controller are two different concepts. .superview gibt Ihnen keinen View-Controller, und das Casting stört nur das Programm.

Während it is possible to find out the current View Controller, ist es sehr unidiomatic in Ihrem Anwendungsfall, weil man nicht sicher sein kann, dass View-Controller hat die signIn() Funktion, und Sie können der „aktuelle View Controller“ nicht einmal sicher, der View-Controller der Ansicht ist.


iOS verwenden in der Regel die "delegate pattern" statt. In Ihrem Fall definieren Sie zunächst ein Protokoll für die signIn() Funktion:

protocol SignInDelegate { 
    func signIn() 
} 

Dann muss die View eine Variable dieses Protokoll liefern. Diese Variable wird Delegat genannt. Wenn Sie sich anmelden möchten, rufen Sie einfach die signIn()-Funktion des Teilnehmers an.

Die Variable sollte eine schwache Referenz zu avoid strong reference cycle sein. Das Protokoll auch needs to be class-bound, sonst wird sich der Compiler beschweren.

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

Als nächstes passen wir das Protokoll an den 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. 
    } 
} 

Wir in der Regel diese Delegierten aussetzen Builder-Schnittstelle, so dass wir einfach den Blick auf den View-Controller verbinden den Delegaten zuweisen .

enter image description here

Dies wird durch adding @IBOutlet an den Delegaten Feld getan. Leider Xcode only recognizes AnyObject/NSObject for IBOutlet, die den ganzen Zweck der Verwendung des Delegiertenmusters für Typ-Sicherheit besiegt. Also müssen wir einen hässlichen Hack einführen, um es für IB zu umgehen. Das Protokoll benötigt nun auch @objc, da das Auflösen dieser IB-Verbindungen die Laufzeit von Objective-C erfordert.

@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

Vielen Dank für die Erklärung, das funktioniert tadellos XD – Luis

+0

Ich würde sagen" Als nächstes machen wir den ViewController das Protokoll übernehmen (oder konform) ", nicht" Weiter passen wir an das Protokoll zum View Controller: ", aber es ist ein Detail –

0

Deklarieren Sie ein Protokoll für die signIn() Funktion und lassen die Eltern Viewcontroller zu diesem Protokoll entsprechen. Dann machen die Eltern Viewcontroller den Delegierten von 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

, wo Sie "den Delegaten" gesetzt haben Es wirft den Fehler, dass "Wert von Typ" MyViewController "nicht geben kann, um" SignInProtocol? " – Luis

+0

Sie müssen die' SignInProtocol' Deklaration festlegen auf dem ViewController: 'Klasse MyViewController: UIViewController, SignInProtocol' – zisoft

Verwandte Themen