退格键和输入新字符后,NSRange `replaceCharactersInRange` 导致应用程序崩溃

Sne*_*eha 3 objective-c uitextfield ios nsrange

我有一个文本字段,并使用shouldChangeCharactersInRange方法来获取值。

这是我的代码:

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

    NSLog(@"Pressing : %@\n", string);
    NSMutableString *text = [NSMutableString stringWithString:textField.text];

    NSLog(@"length: %lu", (unsigned long)range.length);
    NSLog(@"location: %lu\n", (unsigned long)range.location);
    NSLog(@"before text: %@", textField.text);

    [text replaceCharactersInRange:range withString:string];
    NSLog(@"After replacement , Text: %@\n\n", text);

    // My work..

    return YES;
}
Run Code Online (Sandbox Code Playgroud)

我首先将字符“T”添加到文本字段,它工作正常..

2016-03-02 10:06:23.162 MyTextFieldApp[12006:4323645] Pressing : T
2016-03-02 10:06:23.163 MyTextFieldApp[12006:4323645] length: 0
2016-03-02 10:06:23.163 MyTextFieldApp[12006:4323645] location: 0
2016-03-02 10:06:23.163 MyTextFieldApp[12006:4323645] before text: 
2016-03-02 10:06:23.163 MyTextFieldApp[12006:4323645] After replacement , Text: T
Run Code Online (Sandbox Code Playgroud)

然后,我退格它以删除字符,这也很好用。

2016-03-02 10:06:30.979 MyTextFieldApp[12006:4323645] Pressing : 
2016-03-02 10:06:30.980 MyTextFieldApp[12006:4323645] length: 1
2016-03-02 10:06:30.980 MyTextFieldApp[12006:4323645] location: 0
2016-03-02 10:06:30.980 MyTextFieldApp[12006:4323645] before text: T
2016-03-02 10:06:30.981 MyTextFieldApp[12006:4323645] After replacement , Text: 
Run Code Online (Sandbox Code Playgroud)

但是,当我要添加新字符时,它在替换字符串上崩溃。

注意:这一次,范围给出长度 0 和位置 1,而第一次也是当我将 T 添加到空文本字段时,它给出长度 0 和位置 0。

2016-03-02 10:07:02.158 MyTextFieldApp[12006:4323645] Pressing : T
2016-03-02 10:07:02.158 MyTextFieldApp[12006:4323645] length: 0
2016-03-02 10:07:02.159 MyTextFieldApp[12006:4323645] location: 1
2016-03-02 10:07:02.159 MyTextFieldApp[12006:4323645] before text: 
2016-03-02 10:07:02.159 MyTextFieldApp[12006:4323645] *** Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFString replaceCharactersInRange:withString:]: Range or index out of bounds'
Run Code Online (Sandbox Code Playgroud)

我无法检测出问题出在哪里?

par*_*par 5

您的程序正在崩溃,因为您尝试在可变字符串中的无效位置插入数据text

第二次按“T”时,text(从 检索textField.text)的值是一个空字符串(字面意思@"")。然后,您可以传递1 和0的replaceCharactersInRangea 进行调用。当您使用0 的 a 进行调用时,您实际上是在位置 处说“插入字符串” 。该函数仅在大于 0时替换文本。locationlengthreplaceCharactersInRangelengthlocationlength

当您的代码尝试在索引 1 处插入字母“T”时,它无法插入(空字符串的第一个且唯一有效索引为 0),因此程序崩溃。

另外,如果 textField 为空,您的程序不应返回位置 1 和长度 0,这是值得的。一定还有其他事情发生。我用 Swift 编写了示例程序并得到以下输出:

import UIKit

class ViewController: UIViewController {
    var textField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor.blackColor()

        textField = UITextField(frame: CGRectMake(20, 100, 200, 20))
        textField.backgroundColor = UIColor.whiteColor()
        textField.delegate = self

        view.addSubview(textField)
    }
}


extension ViewController: UITextFieldDelegate {
    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        print("range.length: \(range.length), range.location: \(range.location), text: '\(textField.text!)' string: '\(string)'")
        return true
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

range.length: 0, range.location: 0, text: '' string: 'T' // press T
range.length: 1, range.location: 0, text: 'T' string: '' // press backspace
range.length: 0, range.location: 0, text: '' string: 'T' // press T
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我在第二次插入 T 时看到了预期的 0,0 范围。Objective-C 程序的行为应该类似。