Ron Baker
Ron Baker

Reputation: 381

Uncaught Exception in Button

I have a uiview with a couple of elements that I use for a comment function in my app. There is a text field, button, and line separator. Everything renders fine however when I click submit the app crashes and I get this error.

'NSInvalidArgumentException', reason: '-[UIButton copyWithZone:]: unrecognized selector sent to instance 0x7fe58c459620'

I don't see anything wrong with my implementation so this error is a little confusing to me. This is the class for my UIView

import UIKit
protocol CommentInputAccessoryViewDelegate {
    func handleSubmit(for comment: String?)
}

class CommentInputAccessoryView: UIView, UITextFieldDelegate {
    var delegate: CommentInputAccessoryViewDelegate?
    /*
    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
    }
    */

   fileprivate let submitButton: UIButton = {
        let submitButton = UIButton(type: .system)
        submitButton.setTitle("Submit", for: .normal)
        submitButton.setTitleColor(.black, for: .normal)
        submitButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
        submitButton.addTarget(self, action: #selector(handleSubmit), for: .touchUpInside)
        //submitButton.isEnabled = false
        return submitButton
    }()

    lazy var commentTextField: UITextField = {
        let textField = UITextField()
        textField.placeholder = "Add a comment"
        textField.delegate = self
        textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
        return textField
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
       // backgroundColor = .red

        addSubview(submitButton)
        submitButton.anchor(top: topAnchor, left: nil, bottom: bottomAnchor, right:rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 12, width: 50, height: 0)
        addSubview(commentTextField)
        commentTextField.anchor(top: topAnchor, left: leftAnchor, bottom: bottomAnchor, right: submitButton.leftAnchor, paddingTop: 0, paddingLeft: 12, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
        setupLineSeparatorView()

    }
    fileprivate func setupLineSeparatorView(){
        let lineSeparatorView = UIView()
        lineSeparatorView.backgroundColor = UIColor.rgb(red: 230, green: 230, blue: 230)
        addSubview(lineSeparatorView)
        lineSeparatorView.anchor(top:topAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0.5)
    }

    @objc func handleSubmit(for comment: String?){
        guard let commentText = commentTextField.text else{
            return
        }
        delegate?.handleSubmit(for: commentText)
    }

    @objc func textFieldDidChange(_ textField: UITextField) {
        let isCommentValid = commentTextField.text?.count ?? 0 > 0
        if isCommentValid {
            submitButton.isEnabled = true
        }else{
            submitButton.isEnabled = false
        }
    }
    func clearCommentTextField(){
        commentTextField.text = nil
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


}

This is the accompanying class that ultimately handles the submission through a protocol method

    //allows you to gain access to the input accessory view that each view controller has for inputting text
    lazy var containerView: CommentInputAccessoryView = {
        let frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 50)
        let commentInputAccessoryView = CommentInputAccessoryView(frame:frame)
        commentInputAccessoryView.delegate = self
        return commentInputAccessoryView

    }()


    @objc func handleSubmit(for comment: String?){
        guard let comment = comment, comment.count > 0 else{
            return
        }

        let userText = Comments(content: comment, uid: User.current.uid, profilePic: User.current.profilePic!,eventKey: eventKey)
        sendMessage(userText)
        // will clear the comment text field
        self.containerView.clearCommentTextField()
    }

extension NewCommentsViewController {
    func sendMessage(_ message: Comments) {
        ChatService.sendMessage(message, eventKey: eventKey)

    }
}

Upvotes: 0

Views: 58

Answers (2)

vadian
vadian

Reputation: 285082

The associated method for the target/action #selector(handleSubmit) must be

@objc func handleSubmit(_ sender: UIButton) { ...

or

@objc func handleSubmit() { ...

Other forms are not supported.


Does the code compile at all?
Actually you can't use self in the initializer let submitButton: UIButton = { .. }()

Upvotes: 1

Patrick_K
Patrick_K

Reputation: 269

The problem seems to be that UIButton doesn't have a copyWithZone method and that you can't define delegates for UIButtons:

what are the delegate methods available with uibutton

Upvotes: 0

Related Questions