fatihyildizhan
fatihyildizhan

Reputation: 8832

UIFeedback Haptic Engine called more times than was activated

I am using the UIFeedback Haptic Engine with swift 2.3 like:

let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.Warning)

and

let generator = UIImpactFeedbackGenerator(style: .Heavy)
generator.impactOccurred()

Today I got a new kind of error like this, and couldn't find the problem. Do you have any idea?

UIFeedbackHapticEngine _deactivate] called more times than the feedback engine was activated

Details:

Fatal Exception: NSInternalInconsistencyException
0  CoreFoundation                 0x1863e41c0 __exceptionPreprocess
1  libobjc.A.dylib                0x184e1c55c objc_exception_throw
2  CoreFoundation                 0x1863e4094 +[NSException raise:format:]
3  Foundation                     0x186e6e82c -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:]
4  UIKit                          0x18cc43fb8 -[_UIFeedbackEngine _deactivate]
5  UIKit                          0x18cad781c -[UIFeedbackGenerator __deactivateWithStyle:]

Upvotes: 13

Views: 3922

Answers (3)

Bernardo Alecrim
Bernardo Alecrim

Reputation: 67

Just to complete an answer that was already given: what you want to do is either have an OperationQueue or a DispatchQueue that will always be used to call on a FeedbackGenerator's functions. Keep in mind that for your use case, you might have to release the generators, but a minimal example would be:

class HapticsService {

    private let hapticsQueue = DispatchQueue(label: "dev.alecrim.hapticQueue", qos: .userInteractive)

    typealias FeedbackType = UINotificationFeedbackGenerator.FeedbackType

    private let feedbackGeneator = UINotificationFeedbackGenerator()
    private let selectionGenerator = UISelectionFeedbackGenerator()

    func prepareForHaptic() {
        hapticsQueue.async {
            self.feedbackGeneator.prepare()
            self.selectionGenerator.prepare()
        }
    }

    func performHaptic(feedback: FeedbackType) {
        hapticsQueue.async {
            self.feedbackGeneator.notificationOccurred(feedback)
        }
    }

    func performSelectionHaptic() {
        hapticsQueue.async {
            self.selectionGenerator.selectionChanged()
        }
    }

}

This pretty much solved our related crashes in production.

Upvotes: 3

Tal Zion
Tal Zion

Reputation: 6526

Calling generator.impactOccurred() will crash on iOS 11.*. You need to call that on the main thread async.

let generator = UIImpactFeedbackGenerator(style: style)
generator.prepare()

DispatchQueue.main.async {
   generator.impactOccurred()
}

Upvotes: 6

Pau Senabre
Pau Senabre

Reputation: 4209

UIImpactFeedbackGenerator is not thread safe, so make sure you are calling the generator.impactOccurred() synchronously and not in a dispatch_async or in another async thread.

Upvotes: 15

Related Questions