前言
在iOS 15
以后,我们可以通过拖拽一个控件(UITextField
或UITextView
)的形式将其内容复制粘贴到另一个UITextView
,在拖拽之前,如果UITextView
的内容为空,例如:@""
、@" "(含空格)
,在设置代理- (void)textViewDidChange:(UITextView *)textView
时,并且在代理中改变UITextView
的内容后, 或者 - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
返回NO
如果不做特殊处理的话,一定会发生奔溃!
主要奔溃信息是:NSInternalInconsistencyException: Invalid parameter not satisfying: pos
。
奔溃详情如下
1 | CrashDoctor Diagnosis: Application threw exception NSInternalInconsistencyException: Invalid parameter not satisfying: pos |
虽然这种情况很特殊,很少有用户去这样复制粘贴内容,但是一旦用户量大的话,或者用户总是使用这种方式去复制粘贴的话,奔溃的影响还是很大的。
例如,我们将第一个UITextView
拖拽并复制内容Hello world
到另一个UITextView
,即发生奔溃,奔溃演示动画: 动画演示链接 。
环境
Xcode 13.2.1
iPhone 13 Pro Max
(模拟器)iOS 15.2
M1 macOS Monterey 12.2.1
代码重现
新建一个工程,代码如下
1 | @interface ViewController ()<UITextViewDelegate> |
在上面的代码中,我们拖拽textView
并复制其内容Hello world
到textView1
,并在- (void)textViewDidChange:(UITextView *)textView
中设置textView.text = @"Hello";
,即改变textView1
的内容。然后,运行项目,拖拽textView
到textView1
,即发生奔溃。
解决
目前,可以有2
种方案解决。
方案一(推荐)
对要复制到的UITextView
即textView1
设置代理UITextPasteDelegate
,如下
1 | @interface ViewController ()<UITextViewDelegate, UITextPasteDelegate> |
实现代理方法
1 | // MARK: - UITextPasteDelegate |
在这个复制粘贴代理方法中,我们通过在复制粘贴的时候,对UITextView
要复制粘贴的内容进行替换,就可以解决奔溃的问题。
方案二(不推荐)
和方案一唯一不同的是代理方法中的处理方式
1 | - (UITextRange *)textPasteConfigurationSupporting:(id<UITextPasteConfigurationSupporting>)textPasteConfigurationSupporting |
不推荐方案二的原因是,虽然避免了奔溃,我们无法获取到被拖拽的控件textView
中的内容,也就是即使我们拖拽textView
到textView1
,textView1
的内容依旧不会变化。但是要特别注意,有一种情况会变化,如果我们在手机中的任何地方已经复制了文本,然后通过拖拽textView
到textView1
,textView1
会获取到已经复制的文本!例如,我们已经在短信中复制了“好的”
,然后在应用中拖拽textView
到textView1
,如果textView
的内容为空,textView1
的内容就会变成“好的”
,如果不为空,例如textView
的内容为明白,
,那么textView1
的内容就会变成“明白,好的”
。也就是说,通过方案二,拖拽控件永远只是执行粘贴
操作。
注意:方案二需要用真机进行测试。
完整代码
1 | @interface ViewController ()<UITextViewDelegate, UITextPasteDelegate> |
小结
- 拖拽前,如果要复制的
UITextView(这里textView1)
内容不为空(含空格),如"a"、"123"
,无论是在- (void)textViewDidChange:(UITextView *)textView
中改变内容或者- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
返回NO
,一定不会奔溃。 - 拖拽前,如果要复制的
UITextView(这里textView1)
内容为空(如""、" "
),无论是在- (void)textViewDidChange:(UITextView *)textView
中改变内容或者- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
返回NO
,一定会奔溃。 - 方案一和方案二都可以解决奔溃的问题,推荐方案一。