66

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?

Josh Correia
  • 3,807
  • 3
  • 33
  • 50
Eliko
  • 851
  • 2
  • 7
  • 9
  • 5
    Don't disable it. Use the text field delegate methods to prevent the non-numbers from being pasted. – matt Apr 13 '15 at 00:09

14 Answers14

88

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.

Shivam Aditya
  • 392
  • 5
  • 7
TimeString
  • 1,778
  • 14
  • 25
  • 2
    For swift3: class NoPasteUITextField: UITextField { override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { if action == #selector(UIResponderStandardEditActions.paste(_:)) { return false } return super.canPerformAction(action, withSender: sender) } } – Shlomi Fresko Jan 25 '18 at 12:33
  • 1
    Very important part is to return super canperformaction – Travis Delly Apr 24 '19 at 19:58
  • **import Foundation** ... redundant., **import UIKit** .... brings in Foundation – clearlight Aug 15 '22 at 18:18
55

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
}
Andrey Gordeev
  • 30,606
  • 13
  • 135
  • 162
39

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)
    }
}
Nikhil Manapure
  • 3,748
  • 2
  • 30
  • 55
27

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
    }
}
Vasily Bodnarchuk
  • 24,482
  • 9
  • 132
  • 127
  • 1
    ```return action ==``` or ```return allowedActions...``` is incorrect, should be checking for condition and if true ```return super.canPerformAction...``` – Igor Mar 29 '19 at 10:59
  • FYI I've downvoted this because Solution 1 is wrong. You can not override a class property using an extension. From the [docs](https://docs.swift.org/swift-book/LanguageGuide/Extensions.html) **_"Extensions can add new functionality to a type, but they can’t override existing functionality."_** – Leo Dabus Feb 27 '22 at 21:55
7

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.

Matias Jurfest
  • 1,378
  • 16
  • 25
  • 1
    FYI I've downvoted this because you can not override a class property using an extension. From the docs **_"Extensions can add new functionality to a type, but they can’t override existing functionality."_** In other words. This method will never be called. – Leo Dabus Feb 27 '22 at 22:27
6

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.

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
6

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
}
dede.exe
  • 1,300
  • 1
  • 16
  • 27
6

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(_:))
}
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
  • ```return action ==``` is incorrect, should be ```return super.canPerformAction...``` – Igor Mar 29 '19 at 11:00
  • FYI I've downvoted this because you can not override a class property using an extension. From the docs **_"Extensions can add new functionality to a type, but they can’t override existing functionality."_** This method will never be called. – Leo Dabus Feb 27 '22 at 22:29
4
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
    }
}
Vignan Sankati
  • 380
  • 5
  • 15
3

You can create an extension for UITextField and override canPerformAction:

override public func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
        return (action != "paste:") 
}
zaltzy
  • 127
  • 5
  • doesn't it disable paste in ALL textFields in app? – Fyodor Volchyok May 14 '16 at 15:32
  • It does. It seemed to me that this was the intention. If not - my bad (but still an elegant way of doing this). – zaltzy May 16 '16 at 23:04
  • FYI I've downvoted this because you can not override a class property using an extension. From the docs **_"Extensions can add new functionality to a type, but they can’t override existing functionality."_** – Leo Dabus Feb 27 '22 at 22:12
2

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

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)
    }
}
Pramod More
  • 1,220
  • 2
  • 22
  • 51
0

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
}
Renish Dadhaniya
  • 10,642
  • 2
  • 31
  • 56
0

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)
}
Ali Akbarpour
  • 958
  • 2
  • 18
  • 35