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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.