Установите максимальную длину символа UITextField

Как я могу установить максимальное количество символов в UITextField в iPhone SDK при загрузке UIView?

этот невероятно старый ответ очень устарел - теперь ответ тривиален: stackoverflow.com/a/38306929/294884

Fattie 14.11.2017 01:42

Возможный дубликат Установите максимальную длину символа UITextField в Swift

Fattie 14.11.2017 01:42
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
480
2
290 271
45
Перейти к ответу Данный вопрос помечен как решенный

Ответы 45

Вы не можете сделать это напрямую - UITextField не имеет атрибута максимальная длина, но вы можете установить делегат UITextField's, а затем использовать:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

Я согласен, это лучший способ продвинуться вперед, но он остается чем-то вроде взлома. Отправьте в Apple отчет об ошибке, если вы хотите увидеть свойство для длины текста. Меня это тоже определенно интересует.

avocade 12.01.2009 03:12

@avocade, это не взлом: это пример, в котором вам нужно написать базовый код фреймворка, который Apple должна была сделать за вас. В iOS SDK есть МНОЖЕСТВО примеров этого.

Dan Rosenstark 09.11.2011 14:30

Лучше всего настроить уведомление об изменении текста. В вашем -awakeFromNib вашего метода контроллера представления вам понадобится:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(limitTextField:) name:@"UITextFieldTextDidChangeNotification" object:myTextField];

Затем в том же классе добавьте:

- (void)limitTextField:(NSNotification *)note {
    int limit = 20;
    if ([[myTextField stringValue] length] > limit) {
        [myTextField setStringValue:[[myTextField stringValue] substringToIndex:limit]];
    }
}

Затем подключите выход myTextField к вашему UITextField, и он не позволит вам добавлять больше символов после достижения лимита. Не забудьте добавить это в свой метод dealloc:

[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UITextFieldTextDidChangeNotification" object:myTextField];

Хотя я сделал это для удаления ошибок> myTextField.text = [myTextField.text substringToIndex: limit];

Luke 25.11.2014 08:34

Спасибо, август! (Почта)

Вот код, который у меня работает:

#define MAX_LENGTH 20

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (textField.text.length >= MAX_LENGTH && range.length == 0)
    {
        return NO; // return NO to not change text
    }
    else
    {return YES;}
}

К сожалению, это решение не может остановить копирование и вставку пользователей в текстовое поле, что позволяет им обойти ограничение. Ответ Sickpea правильно справляется с этой ситуацией.

Ant 17.04.2012 19:45

Что происходит с людьми, у которых оператор if возвращает NO или YES? Попробуйте это: return! (TextField.text.length> = MAX_LENGTH && range.length == 0);

Matt Parkins 08.10.2014 19:01

или это return textField.text.length < MAX_LENGTH || range.length != 0;

igrek 21.11.2017 19:41

Чтобы завершить ответ август, возможная реализация предложенной функции (см. Делегат UITextField).

Я не тестировал код домина, но мой не застревает, если пользователь достиг предела, и он совместим с новой строкой, которая заменяет меньшую или равную.

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    //limit the size :
    int limit = 20;
    return !([textField.text length]>limit && [string length] > range.length);
}

Чтобы заставить его работать с вырезанием и вставкой строк любой длины, я бы предложил изменить функцию на что-то вроде:

#define MAX_LENGTH 20

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
        NSInteger insertDelta = string.length - range.length;

        if (textField.text.length + insertDelta > MAX_LENGTH)
        {
           return NO; // the new string would be longer than MAX_LENGTH
        }
        else {
            return YES;
        }
    }
Ответ принят как подходящий

Хотя класс UITextField не имеет свойства максимальной длины, относительно просто получить эту функциональность, установив текстовое поле delegate и реализовав следующий метод делегата:

Цель-C

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    // Prevent crashing undo bug – see note below.
    if (range.length + range.location > textField.text.length)
    {
        return NO;
    }
        
    NSUInteger newLength = [textField.text length] + [string length] - range.length;
    return newLength <= 25;
}

Быстрый

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    
    let currentCharacterCount = textField.text?.count ?? 0
    if range.length + range.location > currentCharacterCount {
        return false
    }
    let newLength = currentCharacterCount + string.count - range.length
    return newLength <= 25
}

Перед изменением текстового поля UITextField спрашивает делегата, следует ли изменить указанный текст должен. Текстовое поле на данный момент не изменилось, поэтому мы берем его текущую длину и длину вставляемой строки (либо путем вставки скопированного текста, либо путем ввода одного символа с помощью клавиатуры) за вычетом длины диапазона. Если это значение слишком длинное (более 25 символов в этом примере), верните NO, чтобы запретить изменение.

При вводе одного символа в конце текстового поля range.location будет длиной текущего поля, а range.length будет равен 0, потому что мы ничего не заменяем / не удаляем. Вставка в середину текстового поля просто означает другой range.location, а вставка нескольких символов просто означает, что string содержит более одного символа.

Удаление отдельных символов или вырезание нескольких символов определяется range с ненулевой длиной и пустой строкой. Замена - это просто удаление диапазона непустой строкой.

Замечание об отказе от ошибки "отменить"

Как упоминается в комментариях, в UITextField есть ошибка, которая может привести к сбою.

Если вы вставляете в поле, но вставка предотвращается вашей реализацией проверки, операция вставки все равно записывается в буфере отмены приложения. Если вы затем выполните отмену (встряхнув устройство и подтвердив отмену), UITextField попытается заменить вставленную думает строку пустой строкой. Это приведет к сбою, потому что фактически никогда не вставлял строку в себя. Он попытается заменить несуществующую часть строки.

К счастью, вы можете защитить UITextField от подобного самоубийства. Вам просто нужно убедиться, что диапазон, который он предлагает для замены делает, существует в его текущей строке. Это то, что делает приведенная выше начальная проверка работоспособности.

swift 3.0 с копией и вставкой работает нормально.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let str = (textView.text + text)
        if str.characters.count <= 10 {
            return true
        }
        textView.text = str.substring(to: str.index(str.startIndex, offsetBy: 10))
        return false
    }

Надеюсь, это поможет вам.

Отлично работает ... Как для добавления / удаления.

Chandan Shetty SP 03.02.2011 17:09

Как я могу установить только один UITextView на моем экране? Когда я добавляю его в свой класс, он применяется ко всем текстовым представлениям.

Kyle Clegg 06.08.2012 22:14

Нашел решение, заключив эти две строки в if (textField == _ssn) {} и добавив return YES; в конце метода, что позволит всем остальным UITextFields принимать текст без каких-либо ограничений. Отлично!

Kyle Clegg 07.08.2012 03:48

Очень хороший ответ. Я хотел бы видеть тот, который принимает как можно больше текста, вместо того, чтобы не разрешать его (например, если они попытаются добавить 10 символов, а осталось 9, добавьте первые 9) - например, элементы управления редактированием Windows работают. Но так как я не хочу делать эту работу сам, вы получите мой голос, сэр! :) (надеюсь, Apple скоро добавит это)

eselk 16.10.2012 03:24

Хороший ответ, но тернарный оператор не нужен; можно было просто поставить return newLength <= 25;

jowie 26.02.2013 16:33

Мне это тоже пригодилось. Но если у меня есть 2 разных текстовых поля с разным размером? как я могу это сделать?

doxsi 16.04.2013 15:53

Вау, спасибо большое!! В этом примере максимальная длина устанавливается как 25 символов (25 включительно) только для справки.

coolcool1994 04.09.2013 13:28

Что, если вы просто хотите, чтобы текст не выходил за рамки текстового поля; не все символы одинаковой ширины, верно?

Morkrom 01.10.2013 02:00

@Morkrom Вы правы, взгляните на этот длинный пост про NSString и Unicode

Diogo T 19.03.2014 00:08

Если у кого-то возникнут трудности, убедитесь, что делегат UITextField установлен на self и что <UITextFieldDelegate> установлен в файле заголовка.

Scott Kohlert 04.05.2014 17:00

Отличный пример !! Спасибо! @sickp

valbu17 10.07.2014 20:36

Как упоминает @bcherry, действительно есть ошибка отмены - протестировано с UITextField на iPad iOS 8.1. (+1 к комментарию). Может ли автор что-нибудь добавить по этому поводу, так как это самый популярный ответ? Я счастлив сделать правку, но мне регулярно отказывают! :-)

Benjohn 24.11.2014 19:28

Я добавил чек на сбой и некоторые заметки о нем, взятые отсюда.

Benjohn 24.11.2014 19:55

В системе есть еще одна ошибка: автокоррекция / прогноз обходит метод делегата -textField:shouldChangeCharactersInRange:replacementString. Я думаю, что для полноты ответа об этом стоит упомянуть.

Jakub Vano 14.04.2015 14:52

Этот метод не может предотвратить ввод текста пользователем из автоматического предложения Apple над клавиатурой.

6 1 27.06.2015 10:09

@bherry В Swift проверка случая отмены, похоже, нарушает ввод эмодзи. Разве счетчик (textField.text) на самом деле не должен быть count (textField.text.utf16), чтобы соответствовать отчету objc / uikit в диапазоне (по сравнению с вариантом подсчета строк в Swift)?

rcw3 27.07.2015 20:28

В Swift 2.0 count(textField.text) должен быть textField.text?.characters.count.

funroll 17.09.2015 21:38

Как вызвать этот метод в objc?

Danilo Pádua 23.02.2016 14:39

Для кода Swift сравнение textField.text? .Characters.count с диапазоном добавит ошибку при использовании символов Emoji. Вы должны использовать textField.text? .Utf16.count, чтобы он работал, как описано.

Bogdan Onu 22.11.2016 14:06

Ошибка все еще существует в последних версиях iOS? Я не могу воспроизвести это на своем iPhone с 10.2 и в симуляторе с 8.4.

jesse 27.01.2017 17:17

Извините, я перепроверил, и да, он все еще существует в обоих моих случаях. Я не смог сначала воспроизвести его, потому что, если вы закомментируете «код обхода ошибки», он обнаружит другую проблему, потому что newLength без знака, но результат может быть отрицательным. Таким образом, отрицательные значения становятся очень большими положительными числами. И сравнение возвращает NO, что скрывает ошибку.

jesse 27.01.2017 18:16

Swift 3: func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

Jonny 31.03.2017 12:55

Это быстро не удается при удалении последнего символа, если он состоит из нескольких байтов (например, range.length> 1). К сожалению, классы NSRange и String не очень совместимы, поэтому вы можете столкнуться с подобными проблемами. Вам нужно преобразовать в объекты NSString. Я выложу решение.

Guy Kogus 07.04.2017 20:10

Парень, было ли обновлено решение "Swift 3.0", указанное выше, для решения проблемы "удаления последнего символа"? Также я заметил, что решение «Swift 3.0» предназначено для textView вместо textField?

Robert Smith 28.06.2017 16:53

это ПОЧТИ ДЕСЯТЬ ЛЕТ НЕ ДАТА. хе! теперь это банально: stackoverflow.com/a/38306929/294884

Fattie 14.11.2017 01:43

Подскажите, как правильно ограничить максимальную длину ввода текста? т.е. если я ограничиваю ввод до 3 символов и пытаюсь ввести «で で で», что достигается, когда я нажимаю кнопки клавиатуры «dedede» (каждый «de» преобразуется в «で»), то я не могу ввести последний символ, потому что моя функция проверки считает, что это 4 символа. Вот моя функция проверки: -(BOOL)textField:(UITextField*)tf shouldChangeCharactersInRange:(NSRange)r replacementString:(NSString*)s {return [tf.text stringByReplacingCharactersInRange:r withString:s].length <= 3;} Это можно воспроизвести на японском языке - клавиатура ромадзи

igrek 17.11.2017 20:22

решение - сокращение длины строки в текстовом поле, редактирование закончилось, поэтому авторское решение не обрабатывает этот случай для клавиатуры с японскими ромадзи.

igrek 21.11.2017 12:53

Предположим, у меня есть 2 текстовых поля. Для обоих требуется разный максимальный лимит символов, для одного требуется 10 символов, а для другого - 20 символов. В таком случае, какой подход мне нужно придерживаться. Есть ли способ сделать константу (25 в вашем коде) динамической?

Sachin Rana 28.11.2019 16:23

чтобы всегда иметь возможность удалить текст в случае, если в текстовом поле уже был текст, превышающий допустимую длину, я заменил `` swift return newLength <= 25 '' на `` `` swift return newLength <= 25 || newLength <currentCharacterCount ``, который устранит проблему, при которой пользователь не сможет удалить программно назначенный текст, превышающий maxLenght

Mohamed Hashem 03.12.2019 13:33

Я нашел это быстро и просто

- (IBAction)backgroundClick:(id)sender {
    if (mytext.length <= 7) {
        [mytext resignFirstResponder];
    } else {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Too Big" 
                                                        message:@"Please Shorten Name"
                                                       delegate:nil 
                                              cancelButtonTitle:@"Cancel"
                                              otherButtonTitles:nil];
        [alert show];
        [alert release];
    }
}

Apple не одобряет такое использование UIAlertView. Вы должны зарезервировать предупреждения для важных сообщений и просто запретить ввод, как в принятом ответе.

Dan Abramov 28.12.2012 05:40

Неправильный способ! --- Пользователь узнает о размере ввода после вставки полной строки!

Hemang 30.01.2013 10:28

Используя конструктор интерфейсов, вы можете связать и получить событие «Редактирование изменено» в любой из ваших функций. Теперь там можно поставить чек на длину

- (IBAction)onValueChange:(id)sender 
{
    NSString *text = nil;
    int MAX_LENGTH = 20;
    switch ([sender tag] ) 
    {
        case 1: 
        {
            text = myEditField.text;
            if (MAX_LENGTH < [text length]) {
                myEditField.text = [text substringToIndex:MAX_LENGTH];
            }
        }
            break;
        default:
            break;
    }

}

Я моделирую фактическую замену строки, которая вот-вот должна произойти, чтобы вычислить длину этой будущей строки:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

    NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];

    if ([newString length] > maxLength)
       return NO;

    return YES;
}

Этого должно быть достаточно для решения проблемы (замените 4 желаемым пределом). Просто не забудьте добавить делегата в IB.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
     NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
     return (newString.length<=4);
}

Часто у вас есть несколько полей ввода разной длины.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    int allowedLength;
    switch(textField.tag) {
        case 1: 
            allowedLength = MAXLENGTHNAME;      // triggered for input fields with tag = 1
            break;
        case 2:
            allowedLength = MAXLENGTHADDRESS;   // triggered for input fields with tag = 2
            break;
        default:
            allowedLength = MAXLENGTHDEFAULT;   // length default when no tag (=0) value =255
            break;
    }

    if (textField.text.length >= allowedLength && range.length == 0) {
        return NO; // Change not allowed
    } else {
        return YES; // Change allowed
    }
}

Другие ответы не относятся к случаю, когда пользователь может вставить длинную строку из буфера обмена. Если я вставлю длинную строку, она должна быть только усечена, но показана. Используйте это в своем делегате:

static const NSUInteger maxNoOfCharacters = 5;

-(IBAction)textdidChange:(UITextField * )textField
{
NSString * text = textField.text;

if (text.length > maxNoOfCharacters)
{
    text = [text substringWithRange:NSMakeRange(0, maxNoOfCharacters)];
    textField.text = text;
}

// use 'text'

}

Это правильный способ обработки максимальной длины в UITextField, он позволяет клавише возврата выйти из текстового поля в качестве первого респондента и позволяет пользователю возвращаться, когда они достигают предела

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
int MAX_LENGHT = 5;
    if ([string isEqualToString:@"\n"])
    {
        [textField resignFirstResponder];
        return FALSE;
    }
    else if (textField.text.length > MAX_LENGHT-1)
    {
        if ([string isEqualToString:@""] && range.length == 1)
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    }
    else
    {
        return TRUE;
    }
}

Теперь, сколько символов вы хотите, просто укажите значения

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range   replacementString:(NSString *)string {
     NSUInteger newLength = [textField.text length] + [string length] - range.length;
     return (newLength > 25) ? NO : YES;
  }

Получил до 1 строчки кода :)

Установите делегата текстового представления на «self», затем добавьте <UITextViewDelegate> в свой .h и следующий код в свой .m .... вы можете настроить число «7» так, чтобы оно было таким, каким вы хотите, чтобы ваше МАКСИМАЛЬНОЕ количество символов было.

-(BOOL)textView:(UITextView *)a shouldChangeTextInRange:(NSRange)b replacementText:(NSString *)c {
    return ((a.text.length+c.length<=7)+(c.length<1)+(b.length>=c.length)>0);
}

Этот код учитывает ввод новых символов, удаление символов, выбор символов, затем ввод или удаление, выбор символов и вырезание, вставку в целом и выбор символов и вставку.

Сделанный!






В качестве альтернативы, еще один классный способ написать этот код с битовыми операциями был бы

-(BOOL)textView:(UITextView *)a shouldChangeTextInRange:(NSRange)b replacementText:(NSString *)c {
    return 0^((a.text.length+c.length<=7)+(c.length<1)+(b.length>=c.length));
}

Проблема с некоторыми из приведенных выше ответов: Например, у меня есть текстовое поле, и я должен установить ограничение в 15 символов ввода, затем он останавливается после ввода 15-го символа. но они не позволяют удалить. То есть кнопка удаления тоже не работает. Поскольку я столкнулся с той же проблемой. Вышел с решением, данным ниже. Идеально подходит для меня

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
 if (textField.tag==6)
 {
    if ([textField.text length]<=30)
    {
        return YES;   
    }
    else if ([@"" isEqualToString:string])
    {
        textField.text=[textField.text substringToIndex:30 ];
    }

    return NO;
 }
 else
 {
    return YES;
 }
}

У меня есть текстовое поле, тег которого я установил "6" и я ограничил max char limit = 30; отлично работает в любом случае

Я создал подкласс это UITextFieldLimit:

  • Поддерживается несколько текстовых полей
  • Установить ограничение на длину текста
  • Предотвращение пасты
  • Отображает метку левых символов внутри текстового поля, скрывается, когда вы прекращаете редактирование.
  • Анимация встряхивания, когда не осталось персонажей.

Возьмите UITextFieldLimit.h и UITextFieldLimit.m из этого репозитория GitHub:

https://github.com/JonathanGurebo/UITextFieldLimit

и начинаем тестировать!

Отметьте свой созданный раскадровкой UITextField и свяжите его с моим подклассом с помощью Identity Inspector:

Identity Inspector

Затем вы можете связать его с IBOutlet и установить лимит (по умолчанию 10).


Ваш файл ViewController.h должен содержать: (если вы не хотите изменять настройку, например ограничение)

#import "UITextFieldLimit.h"

/.../

@property (weak, nonatomic) IBOutlet UITextFieldLimit *textFieldLimit; // <--Your IBOutlet

Ваш файл ViewController.m должен быть @synthesize textFieldLimit.


Установите ограничение длины текста в файле ViewController.m:

- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

    [textFieldLimit setLimit:25];// <-- and you won't be able to put more than 25 characters in the TextField.
}

Надеюсь, этот класс тебе поможет. Удачи!

Для небольшой потребности в ограничении символов, я думаю, добавление вашего класса было бы излишним.

Domness 15.07.2014 11:53

Тем не менее усилия оценены.

Reaper 15.12.2014 02:45
(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];

    if ([txt_name.text length]>100)
    {
        return NO;
    }

    return YES;
}

мы можем установить диапазон текстового поля вот так ..

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range  replacementString:(NSString *)string
{
     int setrange = 20;
     return !([textField.text length]>setrange && [string length] > range.length);
}

Это ограничивает количество символов, но также убедитесь, что вы можете вставить в поле до максимального предела.

- (void)textViewDidChange:(UITextView *)textView
{
    NSString* str = [textView text];
    str = [str substringToIndex:MIN(1000,[str length])];
    [textView setText:str];

    if ([str length]==1000) {
        // show some label that you've reached the limit of 1000 characters
    }
}

Следующий код похож на ответ больного, но правильно обрабатывает операции копирования и вставки. Если вы попытаетесь вставить текст, длина которого превышает лимит, следующий код усечет текст, чтобы он соответствовал лимиту, вместо того, чтобы полностью отказаться от операции вставки.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    static const NSUInteger limit = 70; // we limit to 70 characters
    NSUInteger allowedLength = limit - [textField.text length] + range.length;
    if (string.length > allowedLength) {
        if (string.length > 1) {
            // get at least the part of the new string that fits
            NSString *limitedString = [string substringToIndex:allowedLength];
            NSMutableString *newString = [textField.text mutableCopy];
            [newString replaceCharactersInRange:range withString:limitedString];
            textField.text = newString;
        }
        return NO;
    } else {
        return YES;
    }
}

Я реализовал расширение UITextField, чтобы добавить к нему свойство maxLength.

Он основан на Xcode 6 IBInspectables, поэтому вы можете установить ограничение maxLength в построителе интерфейса.

Вот реализация:

UITextField+MaxLength.h

#import <UIKit/UIKit.h>

@interface UITextField_MaxLength : UITextField<UITextFieldDelegate>

@property (nonatomic)IBInspectable int textMaxLength;
@end

UITextField+MaxLength.m

#import "UITextField+MaxLength.h"

@interface UITextField_MaxLength()

@property (nonatomic, assign) id <UITextFieldDelegate> superDelegate;

@end

@implementation UITextField_MaxLength

- (BOOL)textField:(UITextField *) textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

    //validate the length, only if it's set to a non zero value
    if (self.textMaxLength>0) {
        if (range.length + range.location > textField.text.length)
            return NO;

        if (textField.text.length+string.length - range.length>self.textMaxLength) {
            return NO;
        }
    }

    //if length validation was passed, query the super class to see if the delegate method is implemented there
    if (self.superDelegate && [self.superDelegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
        return [self.superDelegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
    }
    else{
        //if the super class does not implement the delegate method, simply return YES as the length validation was passed
        return YES;
    }
}

- (void)setDelegate:(id<UITextFieldDelegate>)delegate {
    if (delegate == self)
        return;
    self.superDelegate = delegate;
    [super setDelegate:self];
}

//forward all non overriden delegate methods
- (id)forwardingTargetForSelector:(SEL)aSelector {
    if ([self.superDelegate  respondsToSelector:aSelector])
        return self.superDelegate;

    return [super forwardingTargetForSelector:aSelector];
}

- (BOOL)respondsToSelector:(SEL)aSelector {
    if ([self.superDelegate respondsToSelector:aSelector])
        return YES;

    return [super respondsToSelector:aSelector];
}
@end

Swift 4

import UIKit

private var kAssociationKeyMaxLength: Int = 0

extension UITextField {
    
    @IBInspectable var maxLength: Int {
        get {
            if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLength) as? Int {
                return length
            } else {
                return Int.max
            }
        }
        set {
            objc_setAssociatedObject(self, &kAssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN)
            addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
        }
    }
    
    @objc func checkMaxLength(textField: UITextField) {
        guard let prospectiveText = self.text,
            prospectiveText.count > maxLength
            else {
                return
        }
        
        let selection = selectedTextRange
        
        let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
        let substring = prospectiveText[..<indexEndOfText]
        text = String(substring)
        
        selectedTextRange = selection
    }
}

Обновлено: исправлена ​​проблема с утечкой памяти.

Отличная идея, Фруо! Я расширил его в своем ответе, чтобы переместить обрезку maxLength в расширение String, чтобы его также можно было использовать для таких вещей, как экземпляры UITextView, и добавить удобную функцию для использования преимуществ этих расширений String в расширении UITextField.

Scott Gardner 01.05.2015 14:34

Разве эта глобальная переменная не создает утечки памяти, удерживая ссылки на все текстовые представления (которые ссылаются на супервизоры до root-)

Ixx 06.09.2016 15:09

@Ixx Я отредактировал, чтобы исправить проблему с утечкой памяти, на которую вы указали + swift 3. Спасибо.

frouo 08.03.2017 18:32

самый красивый способ добиться этого! Спасибо

Victor Choy 06.02.2018 15:34

может ли кто-нибудь предоставить мне его объективную версию

MRizwan33 02.04.2018 14:12

Мне нужна такая же максимальная длина, добавленная в объект инспектора атрибутов c

Nareshkumar Nil 27.08.2018 13:07

Неординарное решение ❤️

Abdul Saleem 08.06.2020 03:15

Великолепное решение! Большое спасибо за то, что поделились?

Pressing_Keys_24_7 24.07.2020 20:47
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if (textField.text.length >= 50) {
        return NO;
    }
    return YES;
}

Это не заставит вас ввести символы больше или равные 50.

Gaurav Gilani 29.04.2015 10:02

Немного помимо ответа на исходный вопрос и расширения ответа Фруо, вот расширения для обрезки строки пробелов до максимальной длины и использования этих расширений String для обрезки UITextField до максимальной длины:

// In String_Extensions.swift

extension String {

  func trimmedString() -> String {
    var trimmedString = self.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
    let components = trimmedString.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).filter { count($0) > 0 }
    return " ".join(components)
  }

  func trimmedStringToMaxLength(maxLength: Int) -> String {
    return trimmedString().substringToIndex(advance(startIndex, min(count(self), maxLength))).trimmedString()
  }

}

// In UITextField_Extensions.swift

private var maxLengthDictionary = [UITextField : Int]()
private var textFieldMaxLength = 20

extension UITextField {

  @IBInspectable var maxLength: Int {
    get {
      if let maxLength = maxLengthDictionary[self] {
        return maxLength
      } else {
        return textFieldMaxLength
      }
    }
    set {
      maxLengthDictionary[self] = newValue < textFieldMaxLength + 1 ? newValue : textFieldMaxLength
    }
  }

  func trimAndLimitToMaxLength() {
    text = text.trimmedStringToMaxLength(maxLength)
  }

}

let someTextField = UITextField()
let someString = "   This   is   a   string   that   is longer than allowable for a text field.   "
someTextField.text = someString
someTextField.trimAndLimitToMaxLength()
println(someTextField.text) // Prints "This is a string tha"
let anotherTextField = UITextField()
anotherTextField.maxLength = 5
anotherTextField.text = someString
anotherTextField.trimAndLimitToMaxLength()
println(anotherTextField.text) // Prints "This"

trimAndLimitToMaxLength() можно использовать в textFieldDidEndEditing(_:) UITextFieldDelegate, чтобы пользователь мог вводить или вставлять более длинную, чем допустимую строку, а затем сокращать ее, а не просто обрезать ввод по максимальной длине. При этом я бы также установил стили текста с атрибутами, чтобы указать любую часть текста, выходящую за пределы допустимой длины (например, [NSBackgroundColorAttributeName : UIColor.redColor(), NSForegroundColorAttributeName : UIColor.whiteColor(), NSStrikethroughStyleAttributeName : NSNumber(int: 1)]

Разве глобальный словарь не создает утечки памяти, удерживая ссылки на все текстовые представления (которые ссылаются на супервизоры до root-)

Ixx 06.09.2016 15:12

Я открыл исходный код подкласса UITextField, STATextField, который предлагает эту функциональность (и многое другое) с помощью свойства maxCharacterLength.

Используйте здесь этот код. RESTRICTED_LENGTH - это длина, которую вы хотите ограничить для текстового поля.

   - (BOOL)textField:(UITextField *)textField     shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (textField == nameTF) {
    int limit = RESTRICTED_LENGTH - 1;
    return !([textField.text length]>limit && [string length] > range.length);
    }
   else
   {
    return YES;
   }

return NO;

}

Для Swift 2.1+

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {

    if (range.length + range.location > textField.text!.characters.count )
    {
        return false;
    }

    let newLength = textField.text!.characters.count + string.characters.count - range.length
    return newLength <= 25
}

Надеюсь, поможет

Swift 2.0 +

Прежде всего создайте класс для этого процесса. Назовем его StringValidator.swift.

Затем просто вставьте в него следующий код.

import Foundation

extension String {

func containsCharactersIn(matchCharacters: String) -> Bool {
let characterSet = NSCharacterSet(charactersInString: matchCharacters)
return self.rangeOfCharacterFromSet(characterSet) != nil
}

func containsOnlyCharactersIn(matchCharacters: String) -> Bool {
let disallowedCharacterSet = NSCharacterSet(charactersInString: matchCharacters).invertedSet
return self.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
}


func doesNotContainCharactersIn(matchCharacters: String) -> Bool {
let characterSet = NSCharacterSet(charactersInString: matchCharacters)
return self.rangeOfCharacterFromSet(characterSet) == nil
}

func isNumeric() -> Bool
{
let scanner = NSScanner(string: self)
scanner.locale = NSLocale.currentLocale()

return scanner.scanDecimal(nil) && scanner.atEnd
}

}

Теперь сохраните класс .....

Применение..

Теперь перейдите в свой класс viewController.swift и сделайте выходы текстового поля как ..

@IBOutlet weak var contactEntryTxtFld: UITextField! //First textfield
@IBOutlet weak var contactEntryTxtFld2: UITextField!   //Second textfield

Теперь перейдите к методу shouldChangeCharactersInRange текстового поля и используйте его, как показано ниже.

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    if string.characters.count == 0 {
        return true
    }
    let latestText = textField.text ?? ""
    let checkAbleText = (latestText as NSString).stringByReplacingCharactersInRange(range, withString: string)


    switch textField {

    case contactEntryTxtFld:
        return checkAbleText.containsOnlyCharactersIn("0123456789") && prospectiveText.characters.count <= 5

    case contactEntryTxtFld2:
        return checkAbleText.containsOnlyCharactersIn("0123456789") && prospectiveText.characters.count <= 5

    default:
        return true
    }

}

Не забудьте установить протокол / методы делегата для текстовых полей.

Позвольте мне объяснить об этом ... Я использую простой процесс расширения строки, который я написал внутри другого класса. Теперь я просто вызываю эти методы расширения из другого класса, где они мне нужны, добавляя проверку и максимальное значение.

Функции...

  1. Он установит максимальный предел конкретного текстового поля.
  2. Он установит тип принимаемых ключей для конкретного текстового поля.

Типы ...

containsOnlyCharactersIn // Принимает только символы.

containsCharactersIn // Принимает комбинацию символов

doesNotContainsCharactersIn // Не принимает символы

Надеюсь, это помогло .... Спасибо..

Я сделал это в Swift для ограничения в 8 символов при использовании цифровой клавиатуры.

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    return !(textField.text?.characters.count == MAX_LENGTH && string != "")
}

Мне пришлось проверить строку! = "", Чтобы кнопка удаления работала на цифровой клавиатуре, иначе она не позволила бы удалить символы в текстовом поле после того, как она достигла своего максимального значения.

Для Xamarin:

YourTextField.ShouldChangeCharacters = 
delegate(UITextField textField, NSRange range, string replacementString)
        {
            return (range.Location + replacementString.Length) <= 4; // MaxLength == 4
        };

Для установки максимальной длины в Swift есть общее решение. С помощью IBInspectable вы можете добавить новый атрибут в Xcode Attribute Inspector.

import UIKit
private var maxLengths = [UITextField: Int]()
extension UITextField {

    @IBInspectable var maxLength: Int {
        get {
            guard let length = maxLengths[self]
            else {
                return Int.max
            }
            return length
        }
        set {
            maxLengths[self] = newValue
            addTarget(
                self,
                action: Selector("limitLength:"),
                forControlEvents: UIControlEvents.EditingChanged
            )
        }
    }

    func limitLength(textField: UITextField) {
        guard let prospectiveText = textField.text
            where prospectiveText.characters.count > maxLength else {
                return
        }
        let selection = selectedTextRange
        text = prospectiveText.substringWithRange(
            Range<String.Index>(prospectiveText.startIndex ..< prospectiveText.startIndex.advancedBy(maxLength))
        )
        selectedTextRange = selection
    }

}

Чистое и идеальное решение

Eduardo 30.01.2017 14:38

Сохранение UITextField в глобальном поле сохранит их в памяти даже после закрытия UIViewController. Это утечка памяти. Не используйте этот метод.

Gunhan 27.02.2019 12:38

Версия Swift 3 // ***** Это НЕ будет работать со Swift 2.x! ***** //

Сначала создайте новый файл Swift: TextFieldMaxLength.swift, а затем добавьте код ниже:

import UIKit

private var maxLengths = [UITextField: Int]()

extension UITextField {

   @IBInspectable var maxLength: Int {

      get {

          guard let length = maxLengths[self] 
             else {
                return Int.max
      }
      return length
   }
   set {
      maxLengths[self] = newValue
      addTarget(
         self,
         action: #selector(limitLength),
         for: UIControlEvents.editingChanged
      )
   }
}
func limitLength(textField: UITextField) {
    guard let prospectiveText = textField.text,
        prospectiveText.characters.count > maxLength
    else {
        return
    }

   let selection = selectedTextRange
   let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
   text = prospectiveText.substring(to: maxCharIndex)
   selectedTextRange = selection
   }
}

а затем вы увидите в раскадровке новое поле (максимальная длина) при выборе любого текстового поля

если у вас остались вопросы, перейдите по этой ссылке: http://www.globalnerdy.com/2016/05/18/ios-programming-trick-how-to-use-xcode-to-set-a-text-fields-maximum-length-visual-studio-style/

Предупреждение, эта глобальная переменная создает утечки памяти, удерживая ссылки на все текстовые представления.

frouo 08.03.2017 18:44

Если ваша цель ограничения количества текста состоит в том, чтобы гарантировать, что текст поместится в UILabel в другом месте, я бы не использовал счетчик символов. Он не работает с некоторыми смайликами (попытка обрезать смайлики двойного размера, скорее всего, приведет к сбою вашего приложения). Это также проблема с некоторыми языками, такими как японский и китайский, которые имеют двухэтапный процесс ввода, когда простой счет просто не работает.

Я создал подкласс UITextField (MPC_CharacterLimitedTextField на github). Вы вводите ему ожидаемую ширину выходной метки, и он будет обрабатывать все языки, смайлики и проблемы с вставкой. Он соберет столько полных символов, сколько поместится на этикетке, независимо от количества символов. В проекте есть демонстрация, поэтому вы можете протестировать ее, чтобы убедиться, что она вам нужна. Надеюсь, это поможет любому, у кого были те же проблемы с длиной вывода, что и у меня.

быстрый 3.0

Этот код работает нормально, когда вы вставляете строку, превышающую допустимое количество символов.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let str = (textView.text + text)
        if str.characters.count <= 10 {
            return true
        }
        textView.text = str.substring(to: str.index(str.startIndex, offsetBy: 10))
        return false
    }

Спасибо за ваши голоса. :)

UITextField, а не UITextView.

Jonny 31.03.2017 12:37

Я хочу добавить к ответу @sickp.

В его коде Swift есть проблема, которая возникает с любым многобайтовым текстом (например, смайликами). NSRange и String в Swift несовместимы, поэтому неприятно, что класс делегата объединяет их. Уловка состоит в том, чтобы просто преобразовать объекты String в NSString. Правильное решение, основанное на том, что написал @sickp, на самом деле таково:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    let currentText = (textField.text as NSString?) ?? NSString()
    let currentCharacterCount = currentText.length
    if range.length + range.location > currentCharacterCount {
        return false
    }
    let newLength = currentText.replacingCharacters(in: range, with: string).characters.count
    return newLength <= 25
}

для Swift 3.1 или новее

сначала добавьте протокол UITextFieldDelegate

нравиться:-

class PinCodeViewController: UIViewController, UITextFieldDelegate { 
.....
.....
.....

}

после этого создайте свой UITextField и установите делегата

Полный опыт: -

import UIKit

class PinCodeViewController: UIViewController, UITextFieldDelegate {

let pinCodetextField: UITextField = {
    let tf = UITextField()
    tf.placeholder = "please enter your pincode"
    tf.font = UIFont.systemFont(ofSize: 15)
    tf.borderStyle = UITextBorderStyle.roundedRect
    tf.autocorrectionType = UITextAutocorrectionType.no
    tf.keyboardType = UIKeyboardType.numberPad
    tf.clearButtonMode = UITextFieldViewMode.whileEditing;
    tf.contentVerticalAlignment = UIControlContentVerticalAlignment.center
 return tf
  }()


 override func viewDidLoad() {
   super.viewDidLoad()
   view.addSubview(pinCodetextField)
    //----- setup your textfield anchor or position where you want to show it----- 


    // after that 
pinCodetextField.delegate = self // setting the delegate

 }
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    return !(textField.text?.characters.count == 6 && string != "")
     } // this is return the maximum characters in textfield 
    }

Даю дополнительный ответ на основе @Frouo. Я думаю, что его ответ - самый красивый. Потому что это обычный элемент управления, который мы можем использовать повторно.

private var kAssociationKeyMaxLength: Int = 0

extension UITextField {

    @IBInspectable var maxLength: Int {
        get {
            if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLength) as? Int {
                return length
            } else {
                return Int.max
            }
        }
        set {
            objc_setAssociatedObject(self, &kAssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN)
            self.addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
        }
    }

    func checkMaxLength(textField: UITextField) {

        guard !self.isInputMethod(), let prospectiveText = self.text,
            prospectiveText.count > maxLength
            else {
                return
        }

        let selection = selectedTextRange
        let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
        text = prospectiveText.substring(to: maxCharIndex)
        selectedTextRange = selection
    }

    //The method is used to cancel the check when use Chinese Pinyin input method.
    //Becuase the alphabet also appears in the textfield when inputting, we should cancel the check.
    func isInputMethod() -> Bool {
        if let positionRange = self.markedTextRange {
            if let _ = self.position(from: positionRange.start, offset: 0) {
                return true
            }
        }
        return false
    }

}

Swift 4

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard let text = textField.text else { return true }
    let newLength = text.count + string.count - range.length
    return newLength <= 10
}

Почему именно guard?

oddRaven 07.04.2018 15:49

проверьте, равен ли текст нулю, если хотите, вы также можете использовать if @oddRaven

Shan Ye 09.04.2018 12:25

Вы также можете сделать это с помощью NotificationCenter в Swift 4

NotificationCenter.default.addObserver(self, selector: #selector(self.handleTextChange(recognizer:)), name: NSNotification.Name.UITextFieldTextDidChange, object: yourTextField)

    @objc func handleTextChange(recognizer: NSNotification) {
            //max length is 50 charater max
            let textField = recognizer.object as! UITextField

            if ((textField.text?.count)! > 50) {
                let newString: String? = (textField.text as NSString?)?.substring(to: 50)
                textField.text = newString

            }         
        }

Используйте расширение ниже, чтобы установить максимальную длину символа для UITextField и UITextView.

Swift 4.0

    private var kAssociationKeyMaxLength: Int = 0
    private var kAssociationKeyMaxLengthTextView: Int = 0
    extension UITextField {


        @IBInspectable var maxLength: Int {
            get {
                if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLength) as? Int {
                    return length
                } else {
                    return Int.max
                }
            }
            set {
                objc_setAssociatedObject(self, &kAssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN)
                addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
            }
        }

        @objc func checkMaxLength(textField: UITextField) {
            guard let prospectiveText = self.text,
                prospectiveText.count > maxLength
                else {
                    return
            }

            let selection = selectedTextRange

            let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
            let substring = prospectiveText[..<indexEndOfText]
            text = String(substring)

            selectedTextRange = selection
        }
    }

UITextView

extension UITextView:UITextViewDelegate {


        @IBInspectable var maxLength: Int {
            get {
                if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLengthTextView) as? Int {
                    return length
                } else {
                    return Int.max
                }
            }
            set {
                self.delegate = self

                objc_setAssociatedObject(self, &kAssociationKeyMaxLengthTextView, newValue, .OBJC_ASSOCIATION_RETAIN)
            }
        }

        public func textViewDidChange(_ textView: UITextView) {
            checkMaxLength(textField: self)
        }
        @objc func checkMaxLength(textField: UITextView) {
            guard let prospectiveText = self.text,
                prospectiveText.count > maxLength
                else {
                    return
            }

            let selection = selectedTextRange

            let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
            let substring = prospectiveText[..<indexEndOfText]
            text = String(substring)

            selectedTextRange = selection
        }
    }

Вы можете установить лимит ниже.

лучший ответ на сегодняшний день, большое спасибо, отличное решение, когда есть много текстовых полей, которым нужна разная длина

Carlos Norena 03.11.2018 17:30

Действительно отличное решение для ограничения ввода текста в текстовое поле и текстовое поле. Сохраните строки кода и время для разработчика ... :)

Sandip Patel - SM 11.01.2019 10:02

Это работает лучше, чем другие найденные мной решения. Например, если у вас есть смайлы в текстовом поле, другие найденные мной расширения при редактировании переходят в конец строки. Но ваш код этого не делает. Спасибо!

Phontaine Judd 31.12.2019 08:25

Как насчет этого простого подхода. Он отлично работает для меня.

extension UITextField {

    func  charactersLimit(to:Int) {

        if (self.text!.count > to) {
            self.deleteBackward()
        }
    }
}

Потом:

someTextField.charactersLimit(to:16)

Swift 4.2 и метод UITextFieldDelegate

Это работает для меня и ограничивает текстовое поле максимальным вводом 8 символов. Надеюсь, NSRange в конечном итоге будет изменен на Range, но пока я счастлив использовать NSString, поскольку создание Range из NSRange включает в себя работу с другим необязательным.

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let text = textField.text ?? ""
    let nsString = text as NSString
    let newText = nsString.replacingCharacters(in: range, with: string)
    return newText.count <= 8
}

Swift 4.2+

Методом реализацияUITextFieldDelegate

  1. ViewController:

    class MyViewController: UIViewController {
    
        let MAX_LENGTH = 256
    
        @IBOutlet weak var myTextField: UITextField!
    
        override viewDidLoad() {
            self.myTextField.delegate = self
        }
    }
    
  2. Делегат:

    extension MyViewController: UITextFieldDelegate {
    
        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            let userText =  textView.text ?? ""
            var newText = ""
            if range.length > 0 {
                let txt = NSString(string: userText)
                if txt.length > 0 {
                    newText = txt.replacingCharacters(in: range, with: text)
                }
            } else {
                newText = userText + text
            }
            return newText.count <= MAX_LENGTH
        }
    
    }
    

Это не компилируется

Lucas 30.08.2019 10:05

@ Лукас, правда? Этот код взят из реального проекта. Вам следует попробовать еще раз.

Pocheshire 30.08.2019 14:46

Работа в Swift 5.2:

 class AngListVC: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var angTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        angTextField.delegate = self
        angTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
      
    }

   func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
           let userText =  angTextField.text ?? ""
           var newText = ""
           if range.length > 0 {
               let txt = NSString(string: userText)
               if txt.length > 0 {
                   newText = txt.replacingCharacters(in: range, with: "")
               }
           } else {
               newText = userText + ""
           }
           return newText.count <= 3
       }

@objc func textFieldDidChange(_ textField: UITextField) {
        print("textFieldDidChange")
   }

Другие вопросы по теме