Внедрение NSUndoManager

#ios #objective-c #xcode #nsundomanager

#iOS #objective-c #xcode #NSUndoManager

Вопрос:

Мне трудно реализовать NSUndoManager, я попытался прочитать документацию Apple по нему, но я не могу понять это. Это то, что я пробовал до сих пор. Я создал приложение, которое рисует линии, соединяя две точки в массиве, я реализовал метод отмены, удалив последний объект, но не могу понять, как реализовать повтор, я наткнулся на NSUndoManager и начал читать его документацию, но я не знаю, как применить его к моей проблеме. Вот код, который у меня есть на данный момент

 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSUInteger taps = [[touches anyObject]tapCount];
    if(taps == 2) {
        [self setNeedsDisplay];
    }
    else {
        if([self.pointsArray count] == 0) {
            self.pointsArray = [[NSMutableArray alloc]init];
            UITouch *t = [touches anyObject];
            CGPoint startLoc = [t locationInView:self];
            [self.pointsArray addObject:[NSValue valueWithCGPoint:startLoc]];
        }
    }
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *t = [touches anyObject];
    CGPoint currentLoc = [t locationInView:self];
    [self.pointsArray addObject:[NSValue valueWithCGPoint:currentLoc]];
    [self setNeedsDisplay];
}

#pragma mark - Undo/Redo Methods
-(void)undo:(id) object {
    [[undoManager prepareWithInvocationTarget:self]redo:object];
    [undoManager setActionName:@"undoLineSegment"];
    [self.pointsArray removeLastObject];
}

-(void)redo:(id)object {
    [self.pointsArray addObject:object];
    [[undoManager prepareWithInvocationTarget:self]undo:object];
    [undoManager setActionName:@"RedoUndoneLineSegment"];
}

- (IBAction)undoButton:(UIButton *)sender {
    [self.undoManager undo];
    [self setNeedsDisplay];
}

- (IBAction)redoButton:(UIButton *)sender {
    [self.undoManager redo];
    [self setNeedsDisplay];
}
  

Я не получаю ошибок, но во время выполнения, когда я нажимаю на кнопки, ничего не происходит. Что я не понимаю в NSUndoManager, так это то, куда идут дела, что такое «объект». Я не объявляю что-то, что мне нужно объявить.

Спасибо,

Комментарии:

1. UndoManager — это стек обратных операций. Таким образом, у вас могут быть «addLineSegment» и «removeLineSegment». Во время «addLineSegment» вы помещаете «removeLineSegment» в стек. Во время «removeLineSegment» вы помещаете «addLineSegment» в стек. Отмена извлекает операцию из стека и выполняет ее. Внедрение дополнительных методов не требуется. Сохраняйте undoButton / redoButton и отменяйте отмену, повтор, отмену LineSegment и RedoUndoneLineSegment.

2. как мне тогда использовать NSUndoManager? Я просто не могу понять, как это применить, так что вы говорите, что я должен сохранить методы UndoButton и redoButton, внутри них я должен сделать это: [[UndoManager prepareWithInvocationTarget:self] и вот что я не понимаю. Должен ли это быть redoButton:object?? Потому что я попробовал это, и он выделяет объект как неправильный. Кажется, я не понимаю документацию или примеры проектов.

3. Все, что должны делать ваши методы undo / redoButton, это указать UndoManager отменить / повторить. Именно в вашем методе touchesBegan вы должны поместить обратную операцию в стек диспетчера отмены. Вы регистрируете операцию отмены в этом методе. И вы бы использовали registerUndoWithTarget

Ответ №1:

Метод touchesMoved будет вызываться несколько раз при рисовании линии, поэтому, если вы зарегистрируете действие отмены в методе touchesMoved, вам необходимо сгруппировать их:

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.undoManager beginUndoGrouping];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.undoManager endUndoGrouping];
}
  

вот пример.

Ответ №2:

Завершите пример в Swift 4. * и Xcode 9.3

 import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var colorsCollectionView: UICollectionView!

    @IBOutlet weak var colorView: UIView!

    var colorsArray = ["green","blue","red","black","yellow","brown","orange","purple","cyan","magenta"]

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func redoAction(_ sender: Any) {
        undoManager?.redo()
    }

    @IBAction func undoAction(_ sender: Any) {
        undoManager?.undo()
    }

    func changeColor(color: UIColor) {

        let oldColor = self.colorView.backgroundColor ?? UIColor.white
        undoManager?.registerUndo(withTarget: self, handler: { (targetSelf) in
            targetSelf.changeColor(color: oldColor)
        })
        colorView.backgroundColor = color
    }

}


extension ViewController: UICollectionViewDelegate,UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return colorsArray.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)

        let label:UILabel = cell.viewWithTag(101) as! UILabel
        label.text = colorsArray[indexPath.row]

        return cell
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let colorName = colorsArray[indexPath.row]

        switch colorName {
        case "green":
            changeColor(color: UIColor.green)
        case "blue":
            changeColor(color: UIColor.blue)
        case "red":
            changeColor(color: UIColor.red)
        case "black":
            changeColor(color: UIColor.black)
        case "yellow":
            changeColor(color: UIColor.yellow)
        case "brown":
            changeColor(color: UIColor.brown)
        case "orange":
            changeColor(color: UIColor.orange)
        case "purple":
            changeColor(color: UIColor.purple)
        case "cyan":
            changeColor(color: UIColor.cyan)
        case "magenta":
            changeColor(color: UIColor.magenta)
        default:
            changeColor(color: UIColor.white)
        }
    }
}
  

введите описание изображения здесь