我有一个简单的Instagram克隆项目,我正在Udemy课程中使用LogInController类和注册类进行跟踪,但当我在iOS 16.2模拟器中使用Xcode 14.2和MacOS蒙特雷12.6.5运行该应用程序时,我收到以下错误消息;

Thread 1: "+[InstagramFirestoreTutorial.LoginController presentRegistrationController]: unrecognized selector sent to class 0x10b086788"

当我点击登录屏幕底部的"没有帐号?注册"时,登录控制器调用一个OBJECTIVE-C函数来服务于点击按钮,并且无法实例化第118行上的注册控制器;

    @objc func presentRegistrationController() {
        let registrationController = RegistrationController()
        navigationController?.pushViewController(registrationController, animated: true)
    }

以下是LoginControler类代码;

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

下面是RegistrationControl类代码;

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

以下是登录屏幕的屏幕截图.

Log In Screen

我注意到,当我在按钮的addTarget方法中将LogInController.self替换为self时,应用程序可以工作,尽管我在Xcode中收到了警告;

Xcode warning

推荐答案

你有一句台词说

button.addTarget(LoginController.self, action: #selector(presentRegistrationController), for: .touchUpInside)

LoginController.self不是目标.此类型的实例应该是目标.它应该是:

private lazy var inviteRegistrationButton: UIButton = {
    let button = UIButton(type: .system)
    button.setAttributedTitle(withQuestion: "Don't have an account?", andAction: "Sign Up")
    button.addTarget(self, action: #selector(presentRegistrationController), for: .touchUpInside)
    return button
}()

总之,您与我们分享的错误消息实际上并不是说"您应该在此上下文中使用LoginController.self",而是"嘿,如果您在这里使用self;在此上下文中,这相当于LoginController.self;这真的是您的意思吗?"不用说,这不是你的意思.因此,我们不应该接受建议的"修复",而是应该更改代码,使self真正引用该实例(例如,通过将其设置为lazy var或通过将此addTarget调用移动到addUISubviews方法).

inviteToLogInButton家公司也有类似的问题.

Swift相关问答推荐

@ MainActor + Combine不一致的编译器错误

Swift:iVar + Equatable上的协议约束

如何为任务扩展的泛型静态函数获得自动类型推理

在visionOS RealityView中使用.GenerateText时,未显示Reality Composer Promaterial 纹理

并发访问SWIFT中数组的非重叠子范围

允许视图在视图内更改

在 SwiftUI 中禁用 Select 器选项

Swift 并发:@MainActor 对象上的通知回调

为什么 String.contains 在我导入 Foundation 时表现不同?

如何在 Xcode 中的 UITests 下以通用方式访问后退栏按钮项?

无法使用锚激活约束

快速的 AES 加密

Swift 2 中的新 @convention(c):我该如何使用它?

使用 DispatchTime.now() + float 延迟?

哪些版本的 Xcode 支持哪些版本的 Swift?

Facebook SDK 4.0 IOS Swift 以编程方式注销用户

<<错误类型>> 奇怪的错误

显示 UIAlertController 的简单 App Delegate 方法(在 Swift 中)

键盘显示时Tableview滚动内容

Swift 5 秒后关闭 UIAlertView