[Swift][TextKit] textStorage(:,willProcessEditing/didprocessEditing:,range:,changeInLength) に渡される情報まとめ

     
⌛️ 2 min.
TextKit2 の構成要素を少しづつ 説明していきます。
この記事では、NSTextStorageDelegate についてです。

環境&対象

以下の環境で動作確認を行なっています。

  • macOS Sonoma Beta 4
  • Xcode 15 Beta 5
  • iOS 17 Beta 4
  • Swift 5.9

NSTextStorageDelegate

NSTextStorageDelegate は、NSTextStorage が変更された時に呼び出される Delegate です。

Apple のドキュメントは、こちら

2つの メソッドが定義されています。
macOS と iOS では少しだけ シグネチャが異なりますが、意味は同じです。

macOS

optional func textStorage(
    _ textStorage: NSTextStorage,
    willProcessEditing editedMask: NSTextStorageEditActions,
    range editedRange: NSRange,
    changeInLength delta: Int
)
optional func textStorage(
    _ textStorage: NSTextStorage,
    didProcessEditing editedMask: NSTextStorageEditActions,
    range editedRange: NSRange,
    changeInLength delta: Int
)

iOS

optional func textStorage(
    _ textStorage: NSTextStorage,
    willProcessEditing editedMask: NSTextStorage.EditActions,
    range editedRange: NSRange,
    changeInLength delta: Int
)
optional func textStorage(
    _ textStorage: NSTextStorage,
    didProcessEditing editedMask: NSTextStorage.EditActions,
    range editedRange: NSRange,
    changeInLength delta: Int
)

willProcessEditing と didProcessEditing は 変更処理の前後で それぞれ呼ばれます。

MEMO

以下の調査は、iOS simulator 上で、didProcessEditing を使って調査しました。
macOS 上でも/willProcessEditing でも 同じだと思いますが確認はしていません。

呼び出し時の引数

willProcessEditing も didProcessEditing も引数は同じです。
それぞれの意味を確認します。

textStorage
変更されている NSTextStorage が渡されてきます。
didProcessEditing/willProcessEditing: NSTextStorage.EditActions/NSTextStorageEditActions
editedCharacters のときは文字が変更され、editedAttributes の時は、文字のアトリビュートが変更されています(その両方が変更されていることもあります)
range: NSRange
変更された 領域情報が NSRange で渡されてきます
changeInLength: Int
変更された文字数が Int で渡されてきます

以降では、NSTextStorage の “01234” という文字列が変更された時に渡されてくる range: NSRange と chandeInLength: Int を確認してみます。

# 以降では、didProcessEditing に渡されてくる値を確認しています。

文字列追加時

通常想定される(?) NSRange と Int が渡されてきます。

つまり、追加された文字列の区間をしめす NSRange と全体の文字数がどの様に変化したかを表す Int が渡されてきました。

先頭に追加

”01234” を “901234” と変更しました。

range: (location: 0, length: 1)
changeInLength: 1

中間に追加

”01234” を “019234” と変更しました。

range: (location: 2, length: 1)
changeInLength: 1

末尾に追加

”01234” を “012349” と変更しました。

range: (location: 5, length: 1)
changeInLength: 1

文字列削除時

文字列削除の時の NSRange には、削除された区間の情報が渡されるかと期待したのですが、違いました。
削除だからといっても、NSRange の length に 負の値が設定されてくることもありませんでした。

NSRange の location は、削除される文字の位置でした。複数文字がまとめて削除されるときは、文字列の先頭位置でした。
NSRange の length は、常に 0 です。

削除された文字数は、changeInLength を確認することが必要となります。

MEMO

なお、Delete でも BackSpace でも同じ値が渡されてきました。

先頭を削除

”01234” を “1234” と変更しました。

range: (location: 0, length: 0)
changeInLength: -1

”01234” を “234” と変更しました。(2文字(01)選んで1操作で削除してます)

range: (location: 0, length: 0)
changeInLength: -2

中間を削除

”01234” を “0134” と変更しました。

range: (location: 2, length: 0)
changeInLength: -1

”01234” を “014” と変更しました。(2文字(23)選んで1操作で削除してます)

range: (location: 2, length: 0)
changeInLength: -2

末尾を削除

”01234” を “0123” と変更しました。

range: (location: 4, length: 0)
changeInLength: -1

”01234” を “012” と変更しました。(2文字(34)選んで1操作で削除してます)

range: (location: 3, length: 0)
changeInLength: -2

置き換え時

置き換え時には、期待通り 置き換えた部分の情報が NSRange として渡されてきます。

置き換えられた範囲が、NSRange として渡されてきて、文字列全体の増減を表す Int が渡されます。
文字列追加の時と同じです。

先頭を置換

”01234” を “91234” と変更しました。

range: (location: 0, length: 1)
changeInLength: 0

”01234” を “891234” と変更しました。

range: (location: 0, length: 2)
changeInLength: 1

中間を置換

”01234” を “01934” と変更しました。

range: (location: 2, length: 1)
changeInLength: 0

”01234” を “018934” と変更しました。

range: (location: 2, length: 2)
changeInLength: 1

末尾を置換

”01234” を “01239” と変更しました。

range: (location: 4, length: 1)
changeInLength: 0

”01234” を “012389” と変更しました。

range: (location: 4, length: 2)
changeInLength: 1

まとめ

NSTextStorageDelegate の textStorage(:,willProcessEditing:,range:,changeInLength:) と
textStorage(:,didProcessEditing:,range:,changeInLength:) が 呼び出される時に受け取る引数について確認しました。

textStorage(:,{will,did}ProcessEditing:,range:,changeInLength:) に渡される引数
  • range は、追加時/削除時で意味が少し異なる
  • changeInLength は、文字列の増減数
  • iOS と macOS ではシグネチャが少し異なるのでコードを共有するときは工夫が必要

説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。

SwiftUI おすすめ本

SwiftUI を理解するには、以下の本がおすすめです。

SwiftUI ViewMatery

SwiftUI で開発していくときに、ViewやLayoutのための適切なmodifierを探すのが大変です。
英語での説明になってしまいますが、以下の”SwiftUI Views Mastery Bundle”という本がビジュアル的に確認して探せるので、便利です。

英語ではありますが、1ページに コードと画面が並んでいるので、非常にわかりやすいです。

View に適用できる modifier もわかりやすく説明されているので、ビューの理解だけではなく、どのような装飾ができるかも簡単にわかります。

超便利です

SwiftUIViewsMastery

販売元のページは、こちらです。

SwiftUI 徹底入門

# SwiftUI は、毎年大きく改善されていますので、少し古くなってしまいましたが、いまでも 定番本です。

Swift学習におすすめの本

詳解Swift

Swift の学習には、詳解 Swift という書籍が、おすすめです。

著者は、Swift の初期から書籍を出していますし、Swift の前に主力言語だった Objective-C という言語についても同様の書籍を出しています。

最新版を購入するのがおすすめです。

現時点では、上記の Swift 5 に対応した第5版が最新版です。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です