54

I am making a registration alertview that has a UITextField in it where the user can enter their registration number. everything is pretty much their, however I would like to remove the copy paste function from the textfield programmatically since their is no InterfaceBuilder version of the textfield I have no idea how to do this..

here Is my UIalertview thus far...

- (void)pleaseRegisterDevice {

    UIAlertView *myAlertView = [[UIAlertView alloc] initWithTitle:@"Please Register Device!" message:@"this gets covered" delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
    regTextField = [[UITextField alloc] initWithFrame:CGRectMake(12.0, 45.0, 260.0, 25.0)];
    [regTextField setBackgroundColor:[UIColor whiteColor]];
    regTextField.textAlignment = UITextAlignmentCenter;
    [myAlertView addSubview:regTextField];
    [myAlertView show];
    [myAlertView release];

}
C.Johns
  • 10,185
  • 20
  • 102
  • 156
  • possible duplicate of [How disable Copy, Cut, Select, Select All in UITextView](http://stackoverflow.com/questions/1426731/how-disable-copy-cut-select-select-all-in-uitextview) – PengOne Jul 14 '11 at 23:16
  • 3
    I don't think this is a duplicate -- this is from a UITextField, the others are for a textView. Some textView solutions don't apply. – Jeff Mar 19 '13 at 06:17
  • For ios 7 http://stackoverflow.com/questions/15745824/uitextfield-how-to-disable-the-paste/15746164#15746164 – iPatel Jul 28 '14 at 10:50
  • [Here you have the same problems with different solutions](https://stackoverflow.com/questions/37606969/disable-copy-paste-in-uitextfield-is-not-working-in-ios-9-x/49403568#49403568) – Pablo Blanco Mar 21 '18 at 12:37

17 Answers17

55

This post has many nice solutions: How disable Copy, Cut, Select, Select All in UITextView

My favourite is to override canPerformAction:withSender::

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    if (action == @selector(paste:))
        return NO;
    return [super canPerformAction:action withSender:sender];
}
Community
  • 1
  • 1
PengOne
  • 48,188
  • 17
  • 130
  • 149
  • 1
    On iOS 7 I'm getting a lot of errors with this. Here's some of the error text: CGContextSetFillColorWithColor: invalid context 0x0. This is a serious error. This application, or a library it uses, is using an invalid context and is thereby contributing to an overall degradation of the system stability and reliability. This notice is a courtesy: please fix this problem. It will become a fatal error in an upcoming update. – Matt Becker Apr 08 '14 at 15:05
  • 1
    for iOS 7 http://stackoverflow.com/questions/15745824/uitextfield-how-to-disable-the-paste/15746164#15746164 – iPatel Jul 28 '14 at 10:51
  • Note that there is also the "replace" menu item which cannot be disabled (in a safe way) from `canPerformAction:withSender`. To turn off paste, disable spell checking via the `UITextField`'s `UIInputTraits` protocol. – Adam Kaplan Jan 10 '16 at 17:49
33

Storyboard users may want to look at this solution, as long as you are ok with subclassing.

I don't think that there is an easy way to achieve this through extensions or protocols.

Swift 3.1

import UIKit

@IBDesignable
class CustomTextField: UITextField {

    @IBInspectable var isPasteEnabled: Bool = true

    @IBInspectable var isSelectEnabled: Bool = true

    @IBInspectable var isSelectAllEnabled: Bool = true

    @IBInspectable var isCopyEnabled: Bool = true

    @IBInspectable var isCutEnabled: Bool = true

    @IBInspectable var isDeleteEnabled: Bool = true

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        switch action {
        case #selector(UIResponderStandardEditActions.paste(_:)) where !isPasteEnabled,
             #selector(UIResponderStandardEditActions.select(_:)) where !isSelectEnabled,
             #selector(UIResponderStandardEditActions.selectAll(_:)) where !isSelectAllEnabled,
             #selector(UIResponderStandardEditActions.copy(_:)) where !isCopyEnabled,
             #selector(UIResponderStandardEditActions.cut(_:)) where !isCutEnabled,
             #selector(UIResponderStandardEditActions.delete(_:)) where !isDeleteEnabled:
            return false
        default:
            //return true : this is not correct
            return super.canPerformAction(action, withSender: sender)
        }
    }
}

Gist link

gujci
  • 1,238
  • 13
  • 21
  • 3
    I think the default case should be "return super.canPerformAction(action, withSender: sender)" instead of "return true". Otherwise, the menu will have all the actions that may not be related to UITextField – Hoang HUA Nov 19 '17 at 19:01
  • @HoangHUA Nice catch – gujci Nov 19 '17 at 22:19
23

For iOS8.0+, Xcode 6.0.1, ARC enabled

Hoping to save a beginner, like myself, some time implementing this...

To implement disabling copy/paste/cut/etc. you must subclass UITextField and override...

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender

To do this...

Create a new class that is a subclass of UITextField (i.e. a new .h and .m files to be included within your app folder). So File->New->"Cocoa Touch Class"->Next->"PasteOnlyUITextField" (for example), subclass of "UITextField"->Next->Create.

Once the .h and .m files are created for our new subclass of UITextField called "PasteOnlyUITextField"...

PasteOnlyUITextField.h

#import <UIKit/UIKit.h>

@interface PasteOnlyUITextField : UITextField

@end

PasteOnlyUITextField.m

#import "PasteOnlyUITextField.h"

@implementation PasteOnlyUITextField

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    if (action == @selector(paste:))
    {
        return true;
    }

    return false;
}

@end

Now make sure you import PasteOnlyUITextField.h where you are going to use it, e.g. YourUIViewController.h file...

#import "PasteOnlyUITextField.h"

Now you must use the subclass, either progrommatically or with identity inspector

PasteOnlyUITextField *pasteOnlyUITextField = [[PasteOnlyUITextField alloc] init...];

or...

Select the UITextField and go to the identity inspector, select its class.

identity inspector

You can change the logic associated with the menu options as you see fit...

Hope this helps! Thanks to all the original contributors.

serge-k
  • 3,394
  • 2
  • 24
  • 55
  • 1
    No, don't return blanket false at the end of the method. Have you logged all of the actions that are received? Quite a few of them – most, even – are private Apple actions that are not your business to control. For example, `_accessibilitySpeak` is probably a feature for sight-impaired users that you do want. `_transliterateChinese` is another interesting one. Better to disable what you definitely don't want and defer to the superclass for others. – Adam Kaplan Jan 10 '16 at 17:53
  • What I wanted is a text field that has only one action, and that action is paste. I have a very basic app. called "C/F Convert" and "Meter Fairy" using this strategy, both approved and reviewed by Apple. My answer gives, what I think, is a more detailed description for subclassing UITextField to accomplish this, and you are free to do what seems best for your application. If Apple wanted to protect this particular class, then they would prevent you from being able to directly subclass it and you would have to create a category to the class to alter the allowed properties or methods. – serge-k Jan 11 '16 at 01:42
  • @AdamKaplan Because TRUE is returned only for PASTE, I think there is no issue in the answer. – Abdurrahman Mubeen Ali Jun 14 '18 at 10:23
  • But the question is asking about the opposite. For that case, @PengOne's answer is correct. – Abdurrahman Mubeen Ali Jun 14 '18 at 10:26
  • 1
    @abdurrahman-mubeen-ali I understand that the answer accomplishes the goal of the question. But it's bad practice to cause unrelated side effects like impacting accessibility. If people copy this answer and it results in their app not working as well for blind/deaf people, that is very bad. PengOne answer is correct and I actually upvoted it years ago! – Adam Kaplan Jun 14 '18 at 16:41
23

I have found a way with swift using extension and associatedObject without subclassing. I use a property readonly to disable paste/cut but this sample can be adapted.

Swift 3 updated as of 27/11/2016

var key: Void?

class UITextFieldAdditions: NSObject {
    var readonly: Bool = false
}

extension UITextField {
    var readonly: Bool {
        get {
           return self.getAdditions().readonly
     } set {
        self.getAdditions().readonly = newValue
    }
}

private func getAdditions() -> UITextFieldAdditions {
    var additions = objc_getAssociatedObject(self, &key) as? UITextFieldAdditions
    if additions == nil {
        additions = UITextFieldAdditions()
        objc_setAssociatedObject(self, &key, additions!, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
    }
    return additions!
}

open override func target(forAction action: Selector, withSender sender: Any?) -> Any? {
    if ((action == #selector(UIResponderStandardEditActions.paste(_:)) || (action == #selector(UIResponderStandardEditActions.cut(_:)))) && self.readonly) {
        return nil
    }
    return super.target(forAction: action, withSender: sender)
}

}

Other Swift (2.2)

import UIKit

var key: Void?

class UITextFieldAdditions: NSObject {
    var readonly: Bool = false
}

extension UITextField {
    var readonly: Bool {
        get {
            return self.getAdditions().readonly
        }
        set {
            self.getAdditions().readonly = newValue
        }
    }

    private func getAdditions() -> UITextFieldAdditions {
        var additions = objc_getAssociatedObject(self, &key) as? UITextFieldAdditions
        if additions == nil {
            additions = UITextFieldAdditions()
            objc_setAssociatedObject(self, &key, additions!, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
        }
        return additions!
    }

    public override func targetForAction(action: Selector, withSender sender: AnyObject?) -> AnyObject? {
        if ((action == Selector("paste:") || (action == Selector("cut:"))) && self.readonly) {
            return nil
        }
        return super.targetForAction(action, withSender: sender)
    }

}
Jesse Onolemen
  • 1,277
  • 1
  • 15
  • 32
dtissera
  • 239
  • 3
  • 3
12

Implement this Method in ViewController.m This Method will help you to disable Options on UITextField.

It Includes paste, select, selectAll and copy option on your Corresponding UITextField.

This method is very useful in case of UITextField when you want to take this for Password or DateOfBirth or whatever you want.

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    if ((_TextField1 isFirstResponder] || [_TextFied2 isFirstResponder]) {
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO];
        }];
    }
    return [super canPerformAction:action withSender:sender];
}
maxshuty
  • 9,708
  • 13
  • 64
  • 77
Himani Sharma
  • 1,550
  • 2
  • 10
  • 12
12

In Swift, If you want your text field to disable all UIResponderStandardEditActions (cut, copy, paste, look up, share, select), use this in UITextFieldDelegate.

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    textField.isUserInteractionEnabled = false
    return true
}

func textFieldDidEndEditing(_ textField: UITextField) {
    textField.isUserInteractionEnabled = true
}
alitosuner
  • 984
  • 1
  • 10
  • 15
9

In iOS 9 we can hide the copy paste bar from keyboard

-(void) customMethod{

   yourTextField.inputAssistantItem.leadingBarButtonGroups = @[];
   yourTextField.inputAssistantItem.trailingBarButtonGroups = @[];

}
Kamil Budziewski
  • 22,699
  • 14
  • 85
  • 105
  • Ha! This is cool. I would caution that you might also be nuking certain options for blind users, Asian-language users, and "define". – Adam Kaplan Jan 10 '16 at 17:55
7

Swift 5 solution:

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

    return true
}
Hugo Jordao
  • 786
  • 8
  • 9
3

Small update of this answer for iOS 10 and earlier (Swift 3):

open override func target(forAction action: Selector, withSender sender: Any?) -> Any? {
    guard isReadonly else {
        return super.target(forAction: action, withSender: sender)
    }

    if #available(iOS 10, *) {
        if action == #selector(UIResponderStandardEditActions.paste(_:)) {
            return nil
        }
    } else {
        if action == #selector(paste(_:)) {
            return nil
        }
    }

    return super.target(forAction: action, withSender: sender)
}
Community
  • 1
  • 1
Raginmari
  • 2,291
  • 23
  • 21
3

Try this in your viewController

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO];
        }];
        return [super canPerformAction:action withSender:sender];
    }
Ali
  • 514
  • 5
  • 16
2

Disable all actions by UITextField subclass.

import UIKit

class CustomTextField: UITextField {
    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return false
    }
}
Water
  • 540
  • 7
  • 7
1

you can extension textview or textfield in swift, like this:

extension UITextView {    
    open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return false
    }
}
nox
  • 11
  • 1
1

If disabled text selection works for you, try this.

class NoMoreSelectionTextField: UITextField {

    override func caretRect(for position: UITextPosition) -> CGRect {
        return CGRect.zero
    }

    override var selectedTextRange: UITextRange? {
        get { return nil }
        set { return }
    }
}
ukaszm
  • 254
  • 2
  • 9
-1

Overriding targetForAction:withSender is best IMHO:

- (id)targetForAction:(SEL)action withSender:(id)sender
{
    if (action == @selector(paste:)) {
        return nil;
    }
    return [super targetForAction:action withSender:sender];
}
DZenBot
  • 4,806
  • 2
  • 25
  • 27
-1

Swift 3.0 version

class NoMenuTextField: UITextField {
    override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
        if (action == #selector(NSObject.paste(_:))) {
            return false
        }
        return super.canPerformAction(action, withSender: sender)
    }
}
Andrey Chernoprudov
  • 1,209
  • 11
  • 13
-3

use for iOS 7 or later

 - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
    [[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO];
}];
return [super canPerformAction:action withSender:sender];

}

Vikas Rajput
  • 1,754
  • 1
  • 14
  • 26
  • 2
    This is identical to [@Ali's answer](https://stackoverflow.com/a/45280129/1107226) from over a month earlier! – leanne Aug 04 '18 at 22:12
  • 1
    I've also used Ali's answer. This should likely be deleted for simplicity and credit to those who put the answer up first. – Stu P. Sep 19 '18 at 14:57
-38

Just set userInteractionEnabled = NO;

Gal Blank
  • 2,070
  • 2
  • 18
  • 18