UITextField에서 문자열 길이 제한

4810 단어
일상적인 개발에서 UITextFiled 컨트롤러에 대해 우리는 항상 UITextField의 길이를 제한해야 한다. 사용자가 임의로 입력한 후에 서버에 전송하는 것을 피하고 문자의 길이가 데이터베이스에서 문자의 길이에 대한 제한을 초과하여 라이브러리를 폭파하게 한다.일반적으로 문자열의 길이를 제한하는 방식은 UITextFieldDelegate에 따라 프록시 방법을 실현하는 것이다.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if (self.frameTextField.text.length >= 5) {
        return NO;
    }
    return YES;
}

이렇게 하면 UITextField의 길이 제한 기능을 실현할 수 있다. 그러나 일반적인 상황에서 우리의 프로그램에는 대량의 UITextField가 포함된다. 만약에 모든 페이지가 이런 "스팸 코드"를 실현한다면 나는 매우 서투른 방법이라고 생각한다. 그리고 같은 페이지에 여러 개의 UITextField가 포함된다면 우리는 현재의 UITextField의 글자 수 제한이 얼마나 되는지 구분해야 한다. 그러면 대량if...else이 생길 것이다.switch...case 스팸 코드.이전의 작업에서 이 기능을 실현하기 위해 제3자가 사용자 정의한 UITextField를 인용한 적이 있다. 사실은 UITextField에서 실현된 컨트롤러를 계승하고 속성 감청을 추가한 것이다.어쨌든 기능은 실현되었지만 최근의 개발에서 저는 다른 사람이 봉인한 컨트롤러를 사용하지 않기로 결정했습니다. 이유는 바로 제가 이렇게 작은 기능을 실현하기 위해 프로젝트에'많은'제3자의 파일을 넣어야 한다고 생각했기 때문입니다. 그리고 보통 이런 제3자가 실현하는 기능은 비교적 많지만 이것은 저에게 아무런 소용이 없습니다. 마지막으로 어떻게 쓰는지 생각해 보겠습니다.

Category 사용


우선 내가 생각한 것은 Category로 이 작은 기능을 실현하는 것이다.계승UITextField을 배제하고 사용자 정의 컨트롤을 실현하는 이유는 간단합니다. 프로젝트에 대량의 UITextField 컨트롤이 만들어졌습니다. 저는 하나하나 교체를 찾고 싶지 않습니다. 사용Category을 하면 이런 상황을 잘 피할 수 있고 코드에 침입성이 없습니다.

문자열 길이를 제한하는 속성 추가

@property (nonatomic, assign)NSInteger maxLenght; Category에서 실례 변수를 만들 수 없기 때문에 runtime의 읽기와 쓰기를 실현하기 위해 maxLenght 방법을 사용해야 합니다.
- (void)setMaxLenght:(NSInteger)maxLenght {
    objc_setAssociatedObject(self, &kMaxLengthKey, @(maxLenght), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSInteger)maxLenght {
    NSNumber * number = objc_getAssociatedObject(self, &kMaxLengthKey);
    return  [number integerValue];
}

위의 이 코드는 내가 설명하지 않겠다. 인터넷에 너무 많다.이로써 우리는 UITextField에 길이를 제한하는 속성을 실현했다. 다음은 이 속성이 운행 과정에서 효력이 발생하면 존재하는 가치를 실현하는 것을 고려한다.여기서 생각나는 UITextFiled의 이벤트: UIControlEventEditingChanged, UITextField의 입력에 변화가 있을 때마다 이 이벤트를 촉발합니다.그래서 우리는 이 사건에 따라 문자열의 길이를 제한하는 방법을 실현할 수 있다.
- (void)addLengthObserverEvent {
    [self addTarget:self action:@selector(valueChange) forControlEvents:UIControlEventEditingChanged];
}
- (void)valueChange {
    if (self.maxLenght > 0 && self.text.length > self.maxLenght) {
        self.text = [self.text substringToIndex:self.maxLenght];
    }
}

이제 가장 중요한 지점에 이르렀습니다. 우리는 어떻게 addLengthObserverEvent 방법을 UITextField 운행 과정에 주입합니까?만약에 우리가 이 방법을public에 공개한다면 우리가 UITextField를 만들 때 이 이벤트를 호출하면 기능이 실현될 수 있다. 그러나 나는 이것이 좋은 해결 방안이라고 생각하지 않는다. 사용하기가 번거롭다. 호출하는 방법은 우리가 관심을 필요로 하는 것이 아니다. 우리가 주의하고 하고 하고 하고 싶은 추가 작업은 maxLength를 설정하는 것이다. 이것은 디자인 제3자가 준수해야 할 규칙에 비교적 부합된다.이 목적을 실현하기 위해서는 런타임이 다시 등장해야 한다.
+ (void)load {
    // Xib,StoryBoard UITextField
    Method  method1 = class_getInstanceMethod([self class], @selector(initWithCoder:));
    Method  method2 = class_getInstanceMethod([self class], @selector(AdapterinitWithCoder:));
    
    // initWithFrame UITextField
    Method method3 = class_getInstanceMethod([self class], @selector(initWithFrame:));
    Method method4 = class_getInstanceMethod([self class], @selector(AdapterinitWithFrame:));
    method_exchangeImplementations(method1, method2);
    
    method_exchangeImplementations(method3, method4);

}

- (instancetype)AdapterinitWithFrame:(CGRect)frame {
    [self AdapterinitWithFrame:frame];
    if (self) {
        // UITextField 。
        [self addLengthObserverEvent];
    }
    return self;
}


- (instancetype)AdapterinitWithCoder:(NSCoder *)aDecoder {
    [self AdapterinitWithCoder:aDecoder];
    if (self) {
        [self addLengthObserverEvent];
    }
    return self;
}

주로rutime의 두 가지 방법Method class_getInstanceMethod(Class cls, SEL name) // method_exchangeImplementations(Method m1, Method m2) // 을 사용했습니다. Xib나 StoryBoard를 사용하여 UITextField를 만들 때 initWithCoder:을 사용합니다. 우리는 AdapterinitWithCoder:를 사용하여 프로그램의 실행을 조정합니다.프로그램이 실행될 때 실제로 호출되는 방법은 AdapterinitWithCoder :이다. 이 방법은 시스템의 initWithCoder : 방법을 실행한 후에 우리가 추가한 논리 코드를 계속 실행하여 동적 주입 효과를 실현한다.여기에 이상한 점이 하나 있다[self AdapterinitWithCoder:aDecoder];. 처음에 내가 이런 코드를 보았을 때 나도 매우 어리둥절하고 사순환에 빠질 것 같았다. 사실은 그렇지 않았다. 왜냐하면 우리는 이미 방법을 교환했기 때문이다. [self AdapterinitWithCoder:aDecoder] 방법은 실제로 실행된 것이다. [self initWithCoder:aDecoder] 시스템을 호출하는 방법은 UITextField를 초기화하는 것이다.+(void)load 방법에 넣은 이유는 + (void)load Objective-c runtime , 우리가 수동으로 호출할 필요가 없기 때문이다.이로써 무침입성은 문자열의 길이를 제한하는 기능을 실현하고 마지막에 runtime의 강함을 찬탄하지 않을 수 없다.

좋은 웹페이지 즐겨찾기