UndoManager

Groot·2022년 10월 10일
0

TIL

목록 보기
80/148
post-thumbnail

TIL

🌱 난 오늘 무엇을 공부했을까?

📌 UndoManager

  • 실행 취소 및 다시 실행을 가능하게 하는 범용 작업 레코더입니다.

📍 Declaration

class UndoManager : NSObject

📍 Overview

  • 실행 취소 작업 등록에 설명된 방법 중 하나를 호출하여 실행 취소 작업을 등록합니다.
  • 변경 중인 객체(또는 해당 객체의 소유자)의 이름을 지정하고 해당 상태를 되돌리기 위한 클로저, 메서드 또는 호출을 제공합니다.

  • 실행 취소 작업을 등록한 후 실행 취소 관리자에서 undo()를 호출하여 마지막 실행 취소 작업의 상태로 되돌릴 수 있습니다.
  • 작업을 실행 취소할 때 UndoManager는 사용자가 redo()를 자동으로 호출할 수 있도록 되돌린 작업을 저장합니다.

  • UndoManager는 일반적으로 UI 상호 작용이 있는 앱에서 사용됩니다. 예를 들어 UIKit은 텍스트 보기 개체에서 실행 취소 및 다시 실행을 구현하므로 응답자 체인을 따라 개체에서 작업을 쉽게 실행 취소하고 다시 실행할 수 있습니다.
  • UndoManager는 또한 여러 종류의 작업을 실행 취소하고 다시 실행하는 데 사용할 수 있는 범용 상태 관리자 역할도 합니다.
  • 예를 들어, 대화형 명령줄 유틸리티는 이 클래스를 사용하여 마지막 명령 실행을 취소하거나 네트워킹 라이브러리가 이전 요청을 무효화하는 다른 요청을 보내 요청을 취소할 수 있습니다, 또는 네트워킹 라이브러리가 이전 요청을 무효화하는 다른 요청을 보내 요청을 취소할 수 있습니다.

📍 Topics

🔗 Registering Undo Operations

func registerUndo<TargetType>(withTarget: TargetType, handler: (TargetType) -> Void)
// 대상이 수신하는 단일 실행 취소 작업을 구현하기 위해 지정된 handler를 등록합니다.

func registerUndo(withTarget: Any, selector: Selector, object: Any?)
// 대상이 수신하는 단일 실행 취소 작업을 구현하기 위해 지정된 대상의 Selector를 등록합니다.

func prepare(withInvocationTarget: Any) -> Any
// 다음 실행 취소 작업의 주제로 지정된 대상을 사용하여 호출 기반 실행 취소를 위해 실행 취소 관리자를 준비합니다.

🔗 Checking Undo Ability

var canUndo: Bool
// 수신자에게 실행 취소할 작업이 있는지 여부를 나타내는 부울 값입니다.

var canRedo: Bool
// 수신자가 다시 실행할 작업이 있는지 여부를 나타내는 부울 값입니다.

🔗 Performing Undo and Redo

func undo()
// 필요한 경우 최상위 실행 취소 그룹을 닫고 undoNestedGroup()을 호출합니다.

func undoNestedGroup() 
// 마지막 실행 취소 그룹(최상위 또는 중첩)에서 실행 취소 작업을 수행하여 다시 실행 스택의 작업을 단일 그룹으로 기록합니다.

func redo()
// redo 스택의 마지막 그룹에서 작업을 수행하고(있는 경우) 실행 취소 스택에 단일 그룹으로 기록합니다.

📌 registerUndo(withTarget:handler:)

📍 Declaration

func registerUndo<TargetType>(
    withTarget target: TargetType,
    handler: @escaping (TargetType) -> Void
) where TargetType : AnyObject

📍 Parameters

🔗 target

  • 실행 취소 작업의 대상입니다.
  • 실행 취소 관리자는 유지 주기를 방지하기 위해 대상에 대한 소유되지 않은 참조를 유지합니다.

🔗 handler

  • 작업이 취소될 때 실행할 클로저입니다.
  • 클로저는 실행 취소 작업의 대상인 단일 인수를 사용합니다.

📍 Discussion

  • registerUndo(withTarget:handler:)를 사용하여 실행 취소 스택에서 실행 취소 작업으로 클로저를 등록합니다.
  • 등록된 클로저는 실행 취소가 호출되고 실행 취소 작업이 발생할 때 실행됩니다.
  • 대상은 실행 취소 관리자가 해당 상태를 실행 취소하거나 다시 실행할 수 있도록 참조 유형이어야 합니다.
var manager = UndoManager()
var bouquetSelection: NSMutableArray = ["lilac", "lavender"]
func pull(flower: String) {
    bouquetSelection.remove(flower)
    manager.registerUndo(withTarget: bouquetSelection) { $0.add(flower) }
}
pull(flower: "lilac")
// bouquetSelection == ["lavender"]
manager.undo()
// bouquetSelection == ["lavender", "lilac"]
  • 대상과의 유지 주기를 방지하려면 동일한 대상을 참조하는 외부 범위의 변수가 아닌 폐쇄 매개변수에 대해 작업하십시오.
  • 예를 들어 위의 코드 목록에서 클로저는 꽃다발 선택에서 직접 작동하지 않고 $0 매개변수에서 작동합니다.

📍 사용해보기

import Foundation

class UndoManagerPractices {
    private let undoManager: UndoManager
    private var model: [String]
    
    init() {
        undoManager = UndoManager()
        model = [String]()
    }
    
    func append(text: String) {
        model.append(text)
        
        undoManager.registerUndo(withTarget: self) {
            $0.remove(text: text)
            print("---삭제 실행 취소---")
        }
    }
    
    func remove(text: String) {
        model.removeAll {
            $0 == text
        }
        
        undoManager.registerUndo(withTarget: self) {
            $0.append(text: text)
            print("---추가 실행 취소---")
        }
    }
    
    func undo() {
        undoManager.undo()
    }
    
    func redo() {
        undoManager.redo()
    }
    
    func printCanUndo() {
        if undoManager.canUndo {
            print("실행 취소할 작업이 있습니다.")
            
            return
        }
        
        print("실행 취소할 작업이 없습니다.")
    }
    
    func printCanRedo() {
        if undoManager.canRedo {
            print("다시 실행할 작업이 있습니다.")
            
            return
        }
        
        print("다시 실행할 작업이 없습니다.")
    }
    
    func printModel() {
        print(model)
    }
}


let undoManagerPractices = UndoManagerPractices()
undoManagerPractices.append(text: "----데이터 추가----")
undoManagerPractices.printCanUndo() // 실행 취소할 작업이 있습니다.
undoManagerPractices.printCanRedo() // 다시 실행할 작업이 없습니다.


undoManagerPractices.remove(text: "----데이터 추가----")


undoManagerPractices.undo() // ---추가 실행---, ---삭제 실행---
undoManagerPractices.printCanUndo() // 실행 취소할 작업이 없습니다.
undoManagerPractices.printCanRedo() // 다시 실행할 작업이 있습니다.


undoManagerPractices.redo() // ---추가 실행---, ---삭제 실행---
undoManagerPractices.printCanUndo() // 실행 취소할 작업이 있습니다.
undoManagerPractices.printCanRedo() // 다시 실행할 작업이 없습니다.

undoManagerPractices.printModel() // []
profile
I Am Groot

0개의 댓글