iosswiftalertshakensundomanager

Alert with Shake to Undo


I want to implement a shake to undo on my iPhone App, in Swift.

For now it works, but it didn't display an Alert asking to validate the undo gesture (with buttons "Cancel" and "Undo"). I can add this alert in the right place myself, but I'm not certain I should. Some articles make me think that the alert should appear automatically, in the undo/redo process, so there's something I missed, perhaps...

Here are the relevant bits of code

In the viewController

override func becomeFirstResponder() -> Bool {
    return true
}

and

override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
   if motion == .motionShake {
       snowflake.undoLastAction()
   }
}

and in my snowflake class, the action is inserting or modifying point in an array, so I store the value before the change in oldPathPoints, then

   // Action du undo
   undoManager?.registerUndo(withTarget: self, handler: {   (targetSelf) in
        snowflake.pathPoints = oldPathPoints
    })

and finally the undo method

func undoLastAction() {
    undoManager?.undo()
    createPath()
    }

Solution

  • So,

    I succeeded to do it (with the help of a 5-years Book from Matt Neuburg!) So, there's nothing to make in the viewController, I deleted becomeFirstResponder and motionEnded.

    All is in the SnowFlake class: I added

        let undoer = UndoManager()
    
        override var undoManager : UndoManager? {
           return self.undoer
        }
        override var canBecomeFirstResponder: Bool { return true }
    

    So I communicate the undoManager I use and the class (a view here) can become firstResponder

    after the manipulation of the view that can be undone (in my case in touchesEnded) , I call

        self.becomeFirstResponder()
    

    I deleted the undoLastAction function (useless now), and changed the undo action to a fonction

        changePathUndoable(newPathPoints: finalPathPoints)
    

    the function is like that

        func changePathUndoable(newPathPoints: [CGPoint]) {
            let oldPathPoints = Snowflake.sharedInstance.pathPoints
            Snowflake.sharedInstance.pathPoints = newPathPoints
            // Action du undo
            undoer.setActionName("cutting")
            undoer.registerUndo(withTarget: self, handler: {   (targetSelf) in
                targetSelf.changePathUndoable(newPathPoints: oldPathPoints)
            })
    
            Snowflake.sharedInstance.createPath()
            self.setNeedsDisplay()
         }
    

    I had to create the function changePathUndoable instead of calling undoer.registerUndo directly just for having the redo action to work (I didn't test redo before).

    I think that all the steps are necessary to do what I wanted: make the view receive the shake event, displays this dialog standard undo dialog box and be able to undo/redo the modifications.