-1

I created a UIViewController called FacebookLoginView with a nib file for it. The nib's File Owner is set to FacebookLoginView. I added two buttons on it and have added the IBActions in the .swift file.

enter image description here

import UIKit
import FacebookLogin

class FacebookLoginView: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    // MARK: - Actions
    @IBAction func didTapCloseButton(_ sender: UIButton) {
        dismiss(animated: true, completion: nil)
    }

    @IBAction func didTapFacebookLoginButton(_ sender: UIButton) {
        print(#function)
    }

}

I instantiate this FacebookLoginView and show it from another view controller like this.

let vc = FacebookLoginView.loadFromNib()
present(vc, animated: true, completion: nil)

extension UIViewController {
    class func loadFromNib<T: UIViewController>() -> T {
        return T(nibName: String(describing: self), bundle: nil)
    }
}

When I tap on either of those buttons on the FacebookLoginView, it crashes with the follwing error.

-[UIViewController didTapFacebookLoginButton:]: unrecognized selector sent to instance 0x14d62940 2017-08-07 20:51:00.997802+0530 RandomFlyer[4010:910999] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIViewController didTapFacebookLoginButton:]: unrecognized selector sent to instance 0x14d62940'

I removed and readded the IBAction connections but the error is still occurring.

Isuru
  • 30,617
  • 60
  • 187
  • 303
  • Cold you show the full error message? It should give the class and the method called. – Larme Aug 07 '17 at 15:01
  • @Larme Updated the question. – Isuru Aug 07 '17 at 15:26
  • 1
    `let vc = FacebookLoginView.loadFromNib()`, Could you check the class of `vc` Seems to be a `UIViewController` and not a `FaceBookLoginView` (I'd name it `FaceBookLoginViewController` btw, to avoid confusing its superclass with `UIView` instead of `UIViewController`). – Larme Aug 07 '17 at 15:28
  • 1
    Agree with @Larme , looks like you did not set the FaceBookLoginView as the class name for your view controller object in xib file . You can do that by selecting controller ( File Owner object ) from the xib and by going to identity inspector tab in the inspector window . – Bharat Jagtap Aug 07 '17 at 15:33
  • @Larme It is coming up as `UIViewController`. I tried to cast it to `FaceBookLoginView` like so - `let vc = FacebookLoginView.loadFromNib() as! FacebookLoginView` but that gives me the error **Could not cast value of type 'UIViewController' (0x398f80ec) to 'RandomFlyer.FacebookLoginView' (0x59be4c).** – Isuru Aug 07 '17 at 15:42
  • I'm not enough familiar with Generics (too old for me in my C++ time) in Swift. So I can't say it's because of your own method or something missing in the .xib file. Could you do the `initWithNibName()` as usual? `FacebookLoginView.init(nibName nibNameOrNil: "FacebookLoginView", bundle:nil)` (in pseudo code, not a Swift master) to check if the issue is on the xib or in the generic method. – Larme Aug 07 '17 at 15:45
  • @Larme That seems to work. Not sure why the generic approach is failing. – Isuru Aug 07 '17 at 15:57

2 Answers2

1

When using the interface builder (IB), make sure every views you have are well connected to your outlets and the set events are existing, like so:

enter image description here

EDIT: While this answer can be applied to the MOST common cause of the common crashes in IB, you might want to edit your question if this does not answer your question.

It says:

-[UIViewController didTapFacebookLoginButton:]: unrecognized selector sent to instance

Your didTapFacebookLoginButton was not found in your class which is the FacebookLoginView, you are actually pointing your Touch Up Inside event to your File Owner. Delete that and follow the sample in my screenshot.

Glenn Posadas
  • 12,555
  • 6
  • 54
  • 95
1

I guess you have not used generics correctly where T is of type UIViewController but the iniatizer requires a concrete type. This should work instead:

extension UIViewController {
    class func loadFromNib() -> Self {
        return self.init(nibName: String(describing: self), bundle: nil)
    }
}
Puneet Sharma
  • 9,369
  • 1
  • 27
  • 33