想定外でした。
2020/12/16追記
より一般的な問題だったので新たに記事にしました。
2020/12/12追記
バグとしてFeedbackAssistantから報告を送っていたのですが、「キーボードがクラッシュしないようにするためのexpected Behaviorだよ(意訳)」という返答をいただきました。
実際、例えば数万、数十万文字に及ぶテキストが一度に選択された場合(全選択では時折起こることですが)、メモリ制限の厳しいKeyboard Extensionでこのような制限がかかることは納得のいくことです。
挙動の概要
動作確認は第1・2世代のiPhoneSE (iOS14.2)において行っています。
タイトルの通り、UITextDocumentProxyのselectedText
は3行以上かつ65文字以上選択していると正しい選択部分を返しません。代わりに最初と最後の2行を結合したものを返してきます。そんなことある?
なぜか最後だけ文字数が32と判定されています。
それぞれの場面でtextDocumentProxy.selectedText?.debugDescription
を出力すると以下のようになります。
Optional("aaaaaaaaaaaaaaaa")
Optional("aaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbb")
Optional("aaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbb\ncccccccccccccccc")
Optional("aaaaaaaaaaaaaaaa\ndddddddddddddddd")
挙動をさらに理解するために次の二例を見ましょう。
非常にわかりにくくて申し訳ないのですが、文字数は改行を含まない設定で算出しているため、改行を含める場合一枚目は64文字、二枚目が65文字です。ここを境に挙動が変わっていることがわかります。
同様の事象は3行でも起こります。
同様に改行を含めて64文字、65文字を境に挙動が変わります。
ハラスメントではないでしょうか。
挙動の問題点
さて、この挙動は実用上どう問題になるでしょうか。
まず、こちら側では得られた二行分のテキストが内部を省略されてしまったものなのか、それともそうでないのか、という判断ができません。従って次のように判断する必要があります。
- 三行以上のテキストがselectedTextに含まれていた場合→問題ない
- 二行のテキストが含まれていた場合→内部の省略かどうか判断ができない
- 一行のテキストが含まれていた場合→問題ない
ちょうど二行のテキストが得られた場合のみ挙動を変えなければならないということです。
しかしユーザ側から見れば、複数行選択した場合に望む挙動を得られる場合と得られない場合が生じることになります。この奇天烈な動作は不具合にしか見えませんし、「3行以上かつ改行含めて65文字以上選択しないで下さい」とはとても頼めません。
従って実際は次のようにせざるを得ません。
❌ 三行以上のテキストがselectedTextに含まれていた場合→諦める
❌ 二行のテキストが含まれていた場合→諦める
⭕️ 一行のテキストが含まれていた場合→用いる
提供できる機能がぐっと制限されますが、やむを得ないでしょう。
恣意的にやらなければ起こらなそうな動作なのに、ドキュメントに書いていないのが本当に意味不明でした。
※こちらの環境によるものの可能性があるので、ぜひ検証をお願いします。