iOS15でUITextViewにテキストをドラッグ&ドロップでクラッシュすることがある


原因が明確には分かっていないのですが、検証した結果をまとめます。
もし原因が特定できたとか、Appleのドキュメントで関連するものがあればぜひコメントで教えてください!

事象

環境

iOS: 15β8、15RC、15.0
Xcode: 12.0, 12.1, 13.0beta, 13.0
上記iOSとXcodeの全ての組み合わせでクラッシュすることを確認

手順

UITextViewにテキストをドラッグ&ドロップする

再現コード

自分が確認した限り、クラッシュは2つのパターンで発生した。

class ViewController: UIViewController {

    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()
        textView.delegate = self
    }
}

extension ViewController: UITextViewDelegate {

    // パターン1: このメソッドでfalseを返す
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        return false
    }

    // パターン2: このメソッド内でtextView.textに代入する
    func textViewDidChange(_ textView: UITextView) {
        textView.text = ""
    }
}

エラーログ

パターン1

2021-09-24 22:46:08.361617+0900 DDCrash[84674:59679328] *** Assertion failure in -[_UITextKitTextPosition compare:], UITextKitTextViewEditingSupport.m:43
2021-09-24 22:46:08.367306+0900 DDCrash[84674:59679328] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: pos'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff203fbbb4 __exceptionPreprocess + 242
    1   libobjc.A.dylib                     0x00007fff2019ebe7 objc_exception_throw + 48
    2   Foundation                          0x00007fff20750c12 _userInfoForFileAndLine + 0
    3   UIKitCore                           0x00007fff253b5b68 -[_UITextKitTextPosition compare:] + 235
    4   UIKitCore                           0x00007fff253a8e77 -[UITextInputController comparePosition:toPosition:] + 85
    5   UIKitCore                           0x00007fff253ca315 -[UITextView comparePosition:toPosition:] + 85
    6   UIKitCore                           0x00007fff2536fc4d -[UITextPasteController _clampRange:] + 634
    7   UIKitCore                           0x00007fff253703c0 __87-[UITextPasteController _performPasteOfAttributedString:toRange:forSession:completion:]_block_invoke + 40
    8   UIKitCore                           0x00007fff253705c8 __87-[UITextPasteController _performPasteOfAttributedString:toRange:forSession:completion:]_block_invoke.174 + 184
    9   UIKitCore                           0x00007fff253b1cec -[UITextInputController _pasteAttributedString:toRange:completion:] + 471
    10  UIKitCore                           0x00007fff25370326 -[UITextPasteController _performPasteOfAttributedString:toRange:forSession:completion:] + 726
    11  UIKitCore                           0x00007fff2536f603 __49-[UITextPasteController _executePasteForSession:]_block_invoke + 299
    12  libdispatch.dylib                   0x000000010edada28 _dispatch_call_block_and_release + 12
    13  libdispatch.dylib                   0x000000010edaec0c _dispatch_client_callout + 8
    14  libdispatch.dylib                   0x000000010edbd376 _dispatch_main_queue_callback_4CF + 1195
    15  CoreFoundation                      0x00007fff2036985d __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    16  CoreFoundation                      0x00007fff203640ba __CFRunLoopRun + 2772
    17  CoreFoundation                      0x00007fff20363103 CFRunLoopRunSpecific + 567
    18  GraphicsServices                    0x00007fff2c851cd3 GSEventRunModal + 139
    19  UIKitCore                           0x00007fff24ffbe63 -[UIApplication _run] + 928
    20  UIKitCore                           0x00007fff25000a53 UIApplicationMain + 101
    21  libswiftUIKit.dylib                 0x00007fff5933d052 $s5UIKit17UIApplicationMainys5Int32VAD_SpySpys4Int8VGGSgSSSgAJtF + 98
    22  DDCrash                             0x000000010ec0a308 $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 104
    23  DDCrash                             0x000000010ec0a297 $s7DDCrash11AppDelegateC5$mainyyFZ + 39
    24  DDCrash                             0x000000010ec0a388 main + 24
    25  dyld                                0x000000010ec2be1e start_sim + 10
    26  ???                                 0x0000000000000001 0x0 + 1
    27  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi: terminating with uncaught exception of type NSException

パターン2

2021-09-24 22:49:41.948006+0900 DDCrash[85889:59687157] *** Assertion failure in -[_UITextKitTextPosition compare:], UITextKitTextViewEditingSupport.m:43
2021-09-24 22:49:41.954547+0900 DDCrash[85889:59687157] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: pos'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff203fbbb4 __exceptionPreprocess + 242
    1   libobjc.A.dylib                     0x00007fff2019ebe7 objc_exception_throw + 48
    2   Foundation                          0x00007fff20750c12 _userInfoForFileAndLine + 0
    3   UIKitCore                           0x00007fff253b5b68 -[_UITextKitTextPosition compare:] + 235
    4   UIKitCore                           0x00007fff253a8e77 -[UITextInputController comparePosition:toPosition:] + 85
    5   UIKitCore                           0x00007fff253ca315 -[UITextView comparePosition:toPosition:] + 85
    6   UIKitCore                           0x00007fff2536fc4d -[UITextPasteController _clampRange:] + 634
    7   UIKitCore                           0x00007fff253703c0 __87-[UITextPasteController _performPasteOfAttributedString:toRange:forSession:completion:]_block_invoke + 40
    8   UIKitCore                           0x00007fff253705c8 __87-[UITextPasteController _performPasteOfAttributedString:toRange:forSession:completion:]_block_invoke.174 + 184
    9   UIKitCore                           0x00007fff253b1cec -[UITextInputController _pasteAttributedString:toRange:completion:] + 471
    10  UIKitCore                           0x00007fff25370326 -[UITextPasteController _performPasteOfAttributedString:toRange:forSession:completion:] + 726
    11  UIKitCore                           0x00007fff2536f603 __49-[UITextPasteController _executePasteForSession:]_block_invoke + 299
    12  libdispatch.dylib                   0x0000000101401a28 _dispatch_call_block_and_release + 12
    13  libdispatch.dylib                   0x0000000101402c0c _dispatch_client_callout + 8
    14  libdispatch.dylib                   0x0000000101411376 _dispatch_main_queue_callback_4CF + 1195
    15  CoreFoundation                      0x00007fff2036985d __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    16  CoreFoundation                      0x00007fff203640ba __CFRunLoopRun + 2772
    17  CoreFoundation                      0x00007fff20363103 CFRunLoopRunSpecific + 567
    18  GraphicsServices                    0x00007fff2c851cd3 GSEventRunModal + 139
    19  UIKitCore                           0x00007fff24ffbe63 -[UIApplication _run] + 928
    20  UIKitCore                           0x00007fff25000a53 UIApplicationMain + 101
    21  libswiftUIKit.dylib                 0x00007fff5933d052 $s5UIKit17UIApplicationMainys5Int32VAD_SpySpys4Int8VGGSgSSSgAJtF + 98
    22  DDCrash                             0x000000010125e2f8 $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 104
    23  DDCrash                             0x000000010125e287 $s7DDCrash11AppDelegateC5$mainyyFZ + 39
    24  DDCrash                             0x000000010125e378 main + 24
    25  dyld                                0x000000010127fe1e start_sim + 10
    26  ???                                 0x0000000000000001 0x0 + 1
    27  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi: terminating with uncaught exception of type NSException

検証したこと

  • iOS14系ではパターン1、パターン2共に発生せず
  • 通常のコピー&ペーストやキーボードからの入力では発生せず
  • UITextViewDelegateの他のメソッドでtextView.textを変更しても発生せず
  • パターン1で戻り値をtrueにすると発生せず
  • パターン2でappend,insert,replaceSubrange,removeによりtextView.textを変更しても発生せず

終わりに

iOS15でアプリを跨ぐドラッグ&ドロップが可能になったことによる何かしらの変更の影響だと思っています。
今後修正される可能性もありますが、UITextViewを使っている方はご注意ください!
UITextViewで文字数の入力制限を設けたい場合、上手い方法を考えないといけないですね…ドラッグ&ドロップをする人なんて少ないだろうし個人的には許容してしまいたいですが😜