1

I’m working on an iOS app where I have an AnyArtboardEvent method that pushes snapshots into my undo/redo stack.

Here’s a simplified version of it:

func AnyArtboardEvent(mergedImaged: UIImage = UIImage()) {
    self.undoRedo?.Add(value: self.SlotViewsToCollection(mergedImage: mergedImaged))
    self.UpdateControllerForActiveSlot()
}

The Add method in my UndoRedo class just appends values to a collection (no recursion there).

func Add(value: SlotViewCollection) {
    var pointerTemp: Int = self.pointer
    pointerTemp = pointerTemp + 1
    self.pointer = pointerTemp
    self.CheckValueAtIndex(value)
    self.EnsureCollectionSize()
}

Issue is that when user finishes interacting with a slider, I call AnyArtboardEvent inside the .ended phase of my touch event handler:

if let touchEvent = event.allTouches?.first {
    switch touchEvent.phase {
    case .ended:
        self.isAnyThingChange = true
        self.AnyArtboardEvent()   // <-- called here
        self.CurrentActiveSlot?.TextLabel?.InitCaLayer(parentView: self)
    default:
        break
    }
}

But after debugging:

When the slider interaction ends, AnyArtboardEvent is called three times.

The first call is expected, but the second and third calls happen immediately afterward (without me explicitly calling them).

I added a symbolic breakpoint and confirmed that all three calls originate from this .ended block.

I also checked the InitCaLayer method (which adds a border CAShapeLayer), but it doesn’t call AnyArtboardEvent.

So far, I couldn’t find anything in my code that would cause AnyArtboardEvent to run multiple times.

Is it possible that touchesEnded / .ended phase is firing multiple times for the slider gesture?

Or could adding layers (CAShapeLayer) indirectly trigger layout passes that fire the touch event handler again?

How can I ensure AnyArtboardEvent is called only once per slider interaction?

2
  • First, are you sure touch event is being called? Or, is AnyArtboardEvent() being called from elsewhere in your code? Put a print("ended") after self.isAnyThingChange = true` and confirm that it's really being triggered 3 times. Commented Sep 4 at 13:57
  • I have made sure that touch event is being called by putting debugger in objc function which runs, further, my whole project doesnt cause AnyArtboardEvent to call!! Commented Sep 5 at 5:42

2 Answers 2

1

@alex you got very close to answer but I found later that real culprit behind this was my call to that slider method. Here it was:

textOpacitySlider.addTarget(self, action: #selector(Opacity), for: .allEvents)

I am new to swift and I asked my manager that if calling for all events would be the issue, but he told me that it shouldn't create any mess but when I changed this to this:

textOpacitySlider.addTarget(self, action: #selector(Opacity), for: .touchDragInside)

It started working finely i.e. calling objc function only once! I think .allEvents was tracking

-When user touches slider
-When he changes it
-And when he left his finger up

That's why my method was being called thrice!

Sign up to request clarification or add additional context in comments.

1 Comment

Oh nice! Thanks for sharing an update on your findings, Muhammad! 🙂
0

touchesEnded itself doesn't fire multiple times for a single touch. What you're seeing is likely multiple touches in event.allTouches , each reporting .ended. For example, if a second finger briefly contacts the slider, or multiple touches exist for some other reason, your handler runs once per touch.

You could potentially just filter the touch you care about:

if let touch = event.allTouches?.first, touch.phase == .ended {
    self.isAnyThingChange = true
    self.AnyArtBoardEvent()
    self.CurrentActiveSlot?.TextLabel?.InitCaLayer(parentView: self)
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.