How to disable pasting in a TextField in Swift?

SwiftUitextfieldPaste

Swift Problem Overview


I've got a TextField with a numberPad and the function runs only if it contains numbers.

The user will crash the app if they paste letters in the TextField and click OK.

How can I disable pasting in the TextField?

Swift Solutions


Solution 1 - Swift

I agree with Leonardo Savio Dabus, if I were you I'd use string checking and just give out a warning, it makes things easier. BUT, if disabling paste option is a fancy feature you really want to put into your app, then you need to do more work. I'll provide the steps below.

Step 1: You need to create another class which extends the UITextField. In this example, I made my CustomUITextField.

import Foundation
import UIKit  //Don't forget this

class CustomUITextField: UITextField {
   override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if action == #selector(UIResponderStandardEditActions.paste(_:)) {
            return false
        }
        return super.canPerformAction(action, withSender: sender)
   }
}

Step 2: Wire the storyboard with your ViewController. You need to declare an IBOutlet as in normal case:

@IBOutlet var textFieldA: CustomUITextField?

Wire the circle next to the @IBOutlet to the TextField in the storyboard. THEN, this is important and easy to be ignored:

  • Go to your storyboard
  • Click the target TextField
  • Select Identity Inspector (the 3rd one)
  • Change the class to CustomUITextField

Quick snapshot is provided below.

enter image description here

That's it, hope this works.

Credit:

Main reference

If you want to know more about the behavior of canPerformAction method, though it's an Objective-C version, the concepts are shared here.

Solution 2 - Swift

For Swift 3 it's changed to:

override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    if action == #selector(copy(_:)) || action == #selector(paste(_:)) {
        return false
    }

    return true
}

Solution 3 - Swift

For Swift 5

UIResponder​Standard​Edit​Actions has been added recently (iOS 10.0+) through which we can safely check if action is "paste" or not.

import UIKit

class NMTextField: UITextField {
    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if action == #selector(UIResponderStandardEditActions.paste(_:)) {
            return false
        }
        return super.canPerformAction(action, withSender: sender)
    }
}

Solution 4 - Swift

Details

  • Xcode 9.1, Swift 4
  • Xcode 10.2 (10E125), 11.2 (11B52), Swift 5

Solution 1

// class TextField: UITextField
extension UITextField {
    
    open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return action == #selector(UIResponderStandardEditActions.cut) || action == #selector(UIResponderStandardEditActions.copy)
    }
}

Solution 1 usage

let textField = UITextField(frame: CGRect(x: 50, y: 120, width: 200, height: 50))
textField.borderStyle = .roundedRect
view.addSubview(textField)

Solution 2

import UIKit

// MARK: Enable/Disable textfield longpress actions

enum ResponderStandardEditActions {
    case cut, copy, paste, select, selectAll, delete
    case makeTextWritingDirectionLeftToRight, makeTextWritingDirectionRightToLeft
    case toggleBoldface, toggleItalics, toggleUnderline
    case increaseSize, decreaseSize

    var selector: Selector {
        switch self {
            case .cut:
                return #selector(UIResponderStandardEditActions.cut)
            case .copy:
                return #selector(UIResponderStandardEditActions.copy)
            case .paste:
                return #selector(UIResponderStandardEditActions.paste)
            case .select:
                return #selector(UIResponderStandardEditActions.select)
            case .selectAll:
                return #selector(UIResponderStandardEditActions.selectAll)
            case .delete:
                return #selector(UIResponderStandardEditActions.delete)
            case .makeTextWritingDirectionLeftToRight:
                return #selector(UIResponderStandardEditActions.makeTextWritingDirectionLeftToRight)
            case .makeTextWritingDirectionRightToLeft:
                return #selector(UIResponderStandardEditActions.makeTextWritingDirectionRightToLeft)
            case .toggleBoldface:
                return #selector(UIResponderStandardEditActions.toggleBoldface)
            case .toggleItalics:
                return #selector(UIResponderStandardEditActions.toggleItalics)
            case .toggleUnderline:
                return #selector(UIResponderStandardEditActions.toggleUnderline)
            case .increaseSize:
                return #selector(UIResponderStandardEditActions.increaseSize)
            case .decreaseSize:
                return #selector(UIResponderStandardEditActions.decreaseSize)
        }
    }
}

class TextField: UITextField {

    private var editActions: [ResponderStandardEditActions: Bool]?
    private var filterEditActions: [ResponderStandardEditActions: Bool]?

    func setEditActions(only actions: [ResponderStandardEditActions]) {
        if self.editActions == nil { self.editActions = [:] }
        filterEditActions = nil
        actions.forEach { self.editActions?[$0] = true }
    }
    
    func addToCurrentEditActions(actions: [ResponderStandardEditActions]) {
        if self.filterEditActions == nil { self.filterEditActions = [:] }
        editActions = nil
        actions.forEach { self.filterEditActions?[$0] = true }
    }

    private func filterEditActions(actions: [ResponderStandardEditActions], allowed: Bool) {
        if self.filterEditActions == nil { self.filterEditActions = [:] }
        editActions = nil
        actions.forEach { self.filterEditActions?[$0] = allowed }
    }

    func filterEditActions(notAllowed: [ResponderStandardEditActions]) {
        filterEditActions(actions: notAllowed, allowed: false)
    }

    func resetEditActions() { editActions = nil }

    open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if let actions = editActions {
            for _action in actions where _action.key.selector == action { return _action.value }
            return false
        }

        if let actions = filterEditActions {
            for _action in actions where _action.key.selector == action { return _action.value }
        }

        return super.canPerformAction(action, withSender: sender)
    }
}

Solution 2 usage

let textField = TextField(frame: CGRect(x: 50, y: 50, width: 200, height: 50))
textField.borderStyle = .roundedRect
view.addSubview(textField)
textField.setEditActions(only: [.copy, .cut, .paste])
//textField.filterEditActions(notAllowed: [.copy, .cut, .paste])
//textField.addToCurrentEditActions(actions: [.paste])

Full sample of the solution 2

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        addTextField(y: 50)
        addTextField(y: 100).setEditActions(only: [.copy, .cut, .paste])
        addTextField(y: 150).filterEditActions(notAllowed: [.copy, .cut, .paste])
    }
    
   @discardableResult func addTextField(y: CGFloat) -> TextField {
        let textField = TextField(frame: CGRect(x: 50, y: y, width: 200, height: 34))
        textField.borderStyle = .roundedRect
        textField.text = "Text"
        view.addSubview(textField)
        return textField
    }
}

Solution 5 - Swift

Swift 4.1 this code is working fine with ViewController.

  1. Disable all option (copy, paste, delete.....etc)

    extension UITextField {

     open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
         return false
     }
    

    }

  2. Enable particular option (select, selectAll... etc)

    extension UITextField {

    open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { return action == #selector(UIResponderStandardEditActions.select(:)) || action == #selector(UIResponderStandardEditActions.selectAll(:)) }

Solution 6 - Swift

Swift 5

If you want to block paste action from every text field in your app

extension UITextField {
    override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return action == #selector(UIResponderStandardEditActions.paste(_:)) ?
            false : super.canPerformAction(action, withSender: sender)
    }
}

EDIT

If you want to block the paste action for text fields that have pickers as input view, add a guard like the following:

extension UITextField {
    override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        guard inputView != nil else { return super.canPerformAction(action, withSender: sender) }

        return action == #selector(UIResponderStandardEditActions.paste(_:)) ?
            false : super.canPerformAction(action, withSender: sender)
    }
}

Warning: the second solution will allow the user to paste on numeric fields.

Solution 7 - Swift

You can just attach an IBAction to your Sent Events (editing changed) of your textfield to remove all non digits from your text as you type as follow:

@IBAction func editingChanged(_ textField: UITextField) {
    textField.text?.removeAll { !("0"..."9" ~= $0) }
}

This will allow the user to paste into the field but it will filter all non digits from the string.

Solution 8 - Swift

In the actual swift version(2.2 going to 3.0) this function code must be refactored to:

override public func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
    if action == #selector(NSObject.copy(_:)) || action == #selector(NSObject.paste(_:)) {
        return false
    }
    
    return true
}

Solution 9 - Swift

class CustomUITextField: UITextField {
    override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if action == #selector(cut(_:)) ||
           action == #selector(copy(_:)) ||  
           action == #selector(UIResponderStandardEditActions.paste(_:)) || 
           action == #selector(UIResponderStandardEditActions.select(_:)) || 
           action == #selector(UIResponderStandardEditActions.selectAll(_:)) || 
           action == #selector(UIResponderStandardEditActions.delete(_:)) ||  
           action == #selector(UIResponderStandardEditActions.makeTextWritingDirectionLeftToRight(_:)) ||  
           action == #selector(UIResponderStandardEditActions.makeTextWritingDirectionRightToLeft(_:)) || 
           action == #selector(UIResponderStandardEditActions.toggleBoldface(_:)) || 
           action == #selector(UIResponderStandardEditActions.toggleItalics(_:)) || 
           action == #selector(UIResponderStandardEditActions.toggleUnderline(_:)) || 
           action == #selector(UIResponderStandardEditActions.increaseSize(_:)) || 
           action == #selector(UIResponderStandardEditActions.decreaseSize(_:)) 
        {
             return false
        };
        return true
    }
}

Solution 10 - Swift

You can create an extension for UITextField and override canPerformAction:

override public func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
		return (action != "paste:") 
}

Solution 11 - Swift

Small edit with a code because when you try to use any function like cut or another one the app will crash . The following code tested on swift 3 and working very well

override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if action == #selector(copy(_:)) || action == #selector(paste(_:)) {
            return false
        }
        return super.canPerformAction(action, withSender: sender)
    }

Solution 12 - Swift

I have created a custom class for textField. I have handled the case when you want to enable/disable actions on textfield. You can customize the code as per your requirement. Set isActionsEnabled true/false for enable/disable actions on textfield.

Prefer to use

> return super.canPerformAction(action, withSender: sender)

instead of

> return true

because returning true might cause a crash in some cases.

Here is my code,

open class MyTextFieldEffect : UITextField {
    
    var isActionsEnabled = true {
        didSet {
            reloadInputViews()
        }
    }

override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        /* disable particular actions
        if (action == #selector(paste(_:)) || action == #selector(copy(_:)) || action == #selector(select(_:)) || action == #selector(cut(_:)) || action == #selector(delete(_:)) || action == #selector(replace(_:withText:))  || action == #selector(select(_:))  || action == #selector(selectAll(_:)) || action == #selector(insertText(_:)) || action == #selector(draw(_:))) && !isActionsEnabled {
            return false
        }
        return super.canPerformAction(action, withSender: sender)
                                           */

       //disable all actions
        if !isActionsEnabled {
            return false
        }

        return super.canPerformAction(action, withSender: sender)
    }
}

Solution 13 - Swift

If you want to Open Date Picker or Picker view on TEXTFIELD click then below code work.

Add below two methods in your class.

//Hide Menu View
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    
    if YOURTEXTFIELD.isFirstResponder {
        DispatchQueue.main.async(execute: {
            (sender as? UIMenuController)?.setMenuVisible(false, animated: false)
        })
        return false
    }
    
    return super.canPerformAction(action, withSender: sender)
}

//MUST Implement

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
            return false
}

Solution 14 - Swift

I did use this code. This is working.

override func canPerformAction(_ action: Selector, withSender sender: Any?)  Bool {

    if YOURTEXTFIELD.isFirstResponder {
        DispatchQueue.main.async(execute: {
            (sender as? UIMenuController)?.setMenuVisible(false, animated: false)
        })
        return false
    }

    return super.canPerformAction(action, withSender: sender)
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionElikoView Question on Stackoverflow
Solution 1 - SwiftTimeStringView Answer on Stackoverflow
Solution 2 - SwiftAndrey GordeevView Answer on Stackoverflow
Solution 3 - SwiftNikhil ManapureView Answer on Stackoverflow
Solution 4 - SwiftVasily BodnarchukView Answer on Stackoverflow
Solution 5 - SwiftHarikant AmiparaView Answer on Stackoverflow
Solution 6 - SwiftMatias JurfestView Answer on Stackoverflow
Solution 7 - SwiftLeo DabusView Answer on Stackoverflow
Solution 8 - Swiftdede.exeView Answer on Stackoverflow
Solution 9 - SwiftTejash JoshiView Answer on Stackoverflow
Solution 10 - SwiftzaltzyView Answer on Stackoverflow
Solution 11 - Swiftwaleed alghamdiView Answer on Stackoverflow
Solution 12 - SwiftPramod MoreView Answer on Stackoverflow
Solution 13 - SwiftRenish DadhaniyaView Answer on Stackoverflow
Solution 14 - SwiftSameen AhmadView Answer on Stackoverflow