I have a simple Instagram clone project that I am following along in a Udemy course with a LogInController class and a Registration class but when I run the app in an iOS 16.2 simulator using Xcode 14.2 with macOS Monterey 12.6.5 I get the following error message;
Thread 1: "+[InstagramFirestoreTutorial.LoginController presentRegistrationController]: unrecognized selector sent to class 0x10b086788"
when I click on "Don't have an account? Sign Up" at the bottom of the Log In screen, the LoginController calls an objective-C function to service the button tap and fails to instantiate the RegistrationController on line 118;
@objc func presentRegistrationController() {
let registrationController = RegistrationController()
navigationController?.pushViewController(registrationController, animated: true)
}
Here is the LoginController class code;
//
// LoginController.swift
// InstagramFirestoreTutorial
//
// Created by *** on 27/02/2023.
//
import UIKit
class LoginController: UIViewController {
// MARK: - Class Properties
private let iconImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "Instagram_logo_white")!)
imageView.contentMode = .scaleAspectFill
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
private let emailTextField: CustomTextField = {
let textField = CustomTextField(placeholder: "Email")
textField.keyboardType = .emailAddress
return textField
}()
private let passwordTextField: CustomTextField = {
let textField = CustomTextField(placeholder: "Password")
textField.isSecureTextEntry = true
return textField
}()
private lazy var stackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [emailTextField, passwordTextField, logInButton, passwordRetrievalButton])
stackView.axis = .vertical
stackView.spacing = 20
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
private let logInButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Log In", for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20.0)
button.backgroundColor = UIColor(named: "logInButton")
button.layer.cornerRadius = 5.0
button.setHeight(50.0)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
private let inviteRegistrationButton: UIButton = {
let button = UIButton(type: .system)
button.setAttributedTitle(withQuestion: "Don't have an account?", andAction: "Sign Up")
button.addTarget(LoginController.self, action: #selector(presentRegistrationController), for: .touchUpInside)
return button
}()
private let passwordRetrievalButton: UIButton = {
let button = UIButton(type: .system)
button.setAttributedTitle(withQuestion: "Forgotten your password?", andAction: "Get help logging in")
return button
}()
// MARK: - Class Lifecycle Methods
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
}
// MARK: - Class Supplementary Methods
private func configureUI() {
view.backgroundColor = .white
navigationController?.navigationBar.isHidden = true
navigationController?.navigationBar.barStyle = .black
configureGradientLayer()
configureSubviews()
}
private func configureSubviews() {
view.addSubview(iconImageView)
NSLayoutConstraint.activate([
iconImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
iconImageView.heightAnchor.constraint(equalToConstant: 80.0),
iconImageView.widthAnchor.constraint(equalToConstant: 120.0),
iconImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 32.0)
])
view.addSubview(stackView)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: iconImageView.bottomAnchor, constant: 32.0),
stackView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 32.0),
stackView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -32.0)
])
view.addSubview(inviteRegistrationButton)
NSLayoutConstraint.activate([
inviteRegistrationButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
inviteRegistrationButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
}
// MARK: - Button Action Selector Functions
@objc func presentRegistrationController() {
let registrationController = RegistrationController()
navigationController?.pushViewController(registrationController, animated: true)
}
}
And here is the RegistrationController class code;
//
// RegistrationController.swift
// InstagramFirestoreTutorial
//
// Created by **** on 27/02/2023.
//
import UIKit
class RegistrationController: UIViewController {
// MARK: - Class Properties
private let profilePhotoButton: UIButton = {
let button = UIButton(type: .system)
button.setImage(UIImage(named: "plus_photo"), for: .normal)
button.tintColor = .white
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
private let emailTextField: CustomTextField = {
let textField = CustomTextField(placeholder: "Email")
textField.keyboardType = .emailAddress
return textField
}()
private let passwordTextField: CustomTextField = {
let textField = CustomTextField(placeholder: "Password")
textField.isSecureTextEntry = true
return textField
}()
private let fullnameTextField = CustomTextField(placeholder: "Fullname")
private let usernameTextField = CustomTextField(placeholder: "Username")
private let signUpButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Sign Up", for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20.0)
button.backgroundColor = UIColor(named: "signUpButton")
button.layer.cornerRadius = 5.0
button.setHeight(50.0)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
private lazy var stackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [emailTextField, passwordTextField, fullnameTextField, usernameTextField, signUpButton])
stackView.axis = .vertical
stackView.spacing = 20
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
private let inviteToLogInButton: UIButton = {
let button = UIButton(type: .system)
button.setAttributedTitle(withQuestion: "Already have an account?", andAction: "Log In")
button.addTarget(RegistrationController.self, action: #selector(presentLogInController), for: .touchUpInside)
return button
}()
// MARK: - Class Lifecycle Methods
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
}
// MARK: - Class Supplementary Methods
private func configureUI() {
configureGradientLayer()
addUISubviews()
navigationController?.navigationBar.isHidden = true
}
private func addUISubviews() {
view.addSubview(profilePhotoButton)
NSLayoutConstraint.activate([
profilePhotoButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
profilePhotoButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 32.0),
profilePhotoButton.widthAnchor.constraint(equalToConstant: 140.0),
profilePhotoButton.heightAnchor.constraint(equalToConstant: 140.0)
])
view.addSubview(stackView)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: profilePhotoButton.bottomAnchor, constant: 32.0),
stackView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 32.0),
stackView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -32.0)
])
view.addSubview(inviteToLogInButton)
NSLayoutConstraint.activate([
inviteToLogInButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
inviteToLogInButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
}
@objc func presentLogInController() {
navigationController?.popViewController(animated: true)
}
}
Here is a screenshot of the Log In screen.
I have noticed that when I replace LogInController.self with self in the button's addTarget method the app works although I do get a warning in Xcode;