SwiftでUndoManagerを使って取り消し・やり直し機能を実装する際、.setActionName
メソッドを見かけることがあります。
このメソッドは一体何のために使うのでしょうか?
本記事では、UndoManagerの.setActionName
について、その意味と使い方を初心者にもわかりやすく解説します。
.setActionNameとは何か?
.setActionName
は、UndoManagerで管理される操作に名前を付けるメソッドです。
基本的な役割
- 取り消し操作にわかりやすい名前を付ける
- メニューやUIで「〜を取り消す」といった表示を可能にする
- ユーザーに何を取り消すのかを明確に伝える
なぜ.setActionNameが必要なのか?
1. ユーザビリティの向上
.setActionName
を使わない場合:
1 2 |
取り消し // 何を取り消すかわからない |
.setActionName
を使った場合:
1 2 3 4 |
「テキスト入力」を取り消し // 具体的で分かりやすい 「画像追加」を取り消し 「色変更」を取り消し |
2. 複数の操作の区別
アプリで複数の種類の操作がある場合、それぞれに適切な名前を付けることで、ユーザーがどの操作を取り消すのか理解しやすくなります。
基本的な使い方
.setActionName
の基本的な使用方法を説明します。
メソッドの呼び出し方は非常にシンプルですが、効果的に使うにはいくつかのポイントがあります。
構文
1 2 |
undoManager.setActionName("アクション名") |
registerUndo
で登録された操作に対して名前を付けるために使用します。
実際の使用例
以下は、簡単なテキストエディタクラスで.setActionName
を使用する実践的な例です。
この例では、テキストの挿入と削除操作にそれぞれ分かりやすい名前を付けています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
import Foundation class DocumentEditor { private let undoManager = UndoManager() private var text = "" func insertText(_ newText: String) { let oldText = text // Undo操作を登録 undoManager.registerUndo(withTarget: self) { editor in editor.text = oldText } // アクション名を設定 undoManager.setActionName("テキスト入力") // 実際の操作を実行 text = newText print("テキストを「\(newText)」に変更") } func deleteText() { let oldText = text undoManager.registerUndo(withTarget: self) { editor in editor.text = oldText } undoManager.setActionName("テキスト削除") text = "" print("テキストを削除") } func undo() { if undoManager.canUndo { let actionName = undoManager.undoActionName undoManager.undo() print("「\(actionName)」を取り消しました") } } } // 使用例 let editor = DocumentEditor() editor.insertText("Hello") editor.deleteText() editor.undo() // 「テキスト削除」を取り消しました |
コードの解説
このサンプルコードでは、以下の流れでUndo機能を実装しています:
- 状態の保存:操作前の状態(
oldText
)を保存 - Undo操作の登録:
registerUndo
で元に戻す処理を登録 - アクション名の設定:
setActionName
で操作に分かりやすい名前を付与 - 実際の操作実行:新しい状態に変更
undo()
メソッドでは、undoActionName
プロパティを使用して、どの操作を取り消すかをユーザーに表示しています。
これにより「テキスト削除を取り消しました」のような具体的なメッセージを表示できます。
実行結果の説明
上記のコードを実行すると:
insertText("Hello")
:テキストが"Hello"に変更され、「テキスト入力」という名前でUndo操作が登録deleteText()
:テキストが空になり、「テキスト削除」という名前でUndo操作が登録undo()
:最後の操作(テキスト削除)が取り消され、テキストが"Hello"に復元
この流れで、ユーザーは何の操作を取り消しているかを明確に理解できます。
.setActionNameは必須か?
答え:必須ではありません
UndoManagerの基本的な取り消し・やり直し機能は、.setActionName
を使わなくても動作します。
1 2 3 4 5 6 7 8 |
// .setActionNameなしでも動作する func simpleUndo() { undoManager.registerUndo(withTarget: self) { target in // 取り消し処理 } // setActionNameを呼ばなくても取り消し機能は働く } |
必須ではないが、.setActionNameを使うべき理由
機能的には必須ではありませんが、.setActionName
を使うべき理由は複数あります。
1. ユーザビリティの大幅な向上
ユーザーが取り消し操作を行う際、何を取り消すのかが明確になります。
特に複雑なアプリケーションでは、直前の操作が何だったかをユーザーが覚えていない場合があります。
1 2 3 4 5 6 |
// アクション名ありの場合 if undoManager.canUndo { let actionName = undoManager.undoActionName showUndoButton(title: "\(actionName)を取り消す") // 「画像回転を取り消す」 } |
2. デバッグの容易さ
開発中にUndo/Redoの動作を確認する際、どの操作が実行されているかを簡単に把握できます。
1 2 3 4 5 6 7 8 9 |
func debugUndoStack() { print("取り消し可能な操作: \(undoManager.undoActionName)") print("やり直し可能な操作: \(undoManager.redoActionName)") // 出力例: // 取り消し可能な操作: テキスト入力 // やり直し可能な操作: 画像削除 } |
3. 保守性の向上
後からコードを見た時や、他の開発者がコードをレビューする際に、どのような操作がUndo対象になっているかが理解しやすくなります。
1 2 3 4 5 6 7 8 9 10 11 |
// 保守性の良いコード例 func rotateImage(angle: Double) { undoManager.registerUndo(withTarget: self) { target in target.rotateImage(angle: -angle) // 逆回転で元に戻す } undoManager.setActionName("画像回転") // 何をしているかが明確 currentAngle += angle updateImageView() } |
4.洗練されたアプリの印象
市販のアプリやApple純正アプリと同じレベルのユーザーエクスペリエンスを提供できます。
ユーザーは「このアプリは作り込まれている」という印象を持ちます。
使わない場合のデメリット
.setActionName
を設定しない場合、以下のような問題が発生します。
1 2 3 4 5 6 |
// アクション名なしの場合 print(undoManager.undoActionName) // ""(空文字) // メニューでの表示 // "Undo" → 何を取り消すかわからない |
具体的なデメリット:
- ユーザーの混乱:何を取り消すのかわからず、実行を躊躇する
- 誤操作の増加:予期しない結果になる可能性
- アプリの品質低下:未完成な印象を与える
例えば、テキストエディタで複数の操作を行った後:
1 2 3 4 5 6 7 8 9 10 |
// 1. テキスト入力 // 2. 書式変更 // 3. 画像挿入 // アクション名なしの場合 undoButton.title = "取り消し" // どれを取り消すかわからない // アクション名ありの場合 undoButton.title = "「画像挿入」を取り消し" // 明確! |
実装のベストプラクティス
.setActionName
を効果的に使うための重要なポイントを説明します。
1. 分かりやすい名前を付ける
アクション名は、ユーザーが理解しやすい具体的で分かりやすい名前にすることが重要です。
抽象的過ぎたり、技術的すぎる名前は避けましょう。
1 2 3 4 5 6 7 8 9 10 |
// ❌ 悪い例 undoManager.setActionName("action") // 抽象的すぎる undoManager.setActionName("処理") // 何の処理かわからない undoManager.setActionName("update") // 技術的すぎる // ✅ 良い例 undoManager.setActionName("テキスト編集") // 具体的で分かりやすい undoManager.setActionName("画像回転") // 操作内容が明確 undoManager.setActionName("フォント変更") // ユーザー目線の表現 |
ユーザーがメニューで「『テキスト編集』を取り消す」と表示された時に、すぐに理解できる名前を心がけましょう。
2. 一貫性を保つ
アプリケーション全体を通して、命名規則を統一することで、ユーザーにとって予測可能なインターフェースを提供できます。
1 2 3 4 5 6 7 8 9 10 |
// 命名規則を統一する undoManager.setActionName("テキスト入力") // 動詞+目的語 undoManager.setActionName("画像削除") // 動詞+目的語 undoManager.setActionName("色変更") // 目的語+動詞 // または全て「〜の〜」形式で統一 undoManager.setActionName("テキストの入力") undoManager.setActionName("画像の削除") undoManager.setActionName("色の変更") |
チーム開発では、この命名規則をドキュメント化しておくと良いでしょう。
3. タイミングに注意
.setActionName
を呼び出すタイミングは重要です。
正しい順序で実行しないと、期待通りに動作しません。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
func performAction() { // 1. まずUndo操作を登録 undoManager.registerUndo(withTarget: self) { target in // 取り消し処理 } // 2. 次にアクション名を設定 undoManager.setActionName("適切な名前") // 3. 最後に実際の操作を実行 // 実際の処理... } |
この順序が重要な理由:
registerUndo
でUndoスタックに操作を追加setActionName
でその操作に名前を付ける- 最後に実際の処理を実行して状態を変更
順序を間違えると、アクション名が正しく設定されない場合があります。
まとめ
UndoManagerの.setActionName
について重要なポイント:
- 目的:取り消し操作にわかりやすい名前を付けるため
- 必須性:機能的には必須ではないが、UX向上のために強く推奨
- 効果:ユーザーが何を取り消すかを明確に理解できる
- 実装:
registerUndo
の直後に呼び出すのが基本
.setActionName
は小さな機能ですが、ユーザーエクスペリエンスに大きな影響を与えます。
洗練されたアプリを作りたいなら、ぜひ積極的に活用してみましょう!