Downside
I am creating a multi-touch ios app that entails monitoring a number of contact factors and interacting with relative pads. The applying’s operate is to reply to contact occasions, replace the ‘contact level standing’ and carry out pad lighting and do another issues. I’ve encountered some issues with multi-touch administration and standing updates and pad lighting, and I hope to get some assist. Specificlly, after I put two fingers(two touches) on the display(regard much less the order), the pad similar to your finger will gentle up (that is what i need) and do another factor utilizing callback function1. Once I raise my finger 1 / touch1 (irrespective of which one), the pad similar to touch1 must be darkened, however it’s not darkened, and the corresponding callback operate (that’s, inside touchesEnded(with touch1)) will not be referred to as. Solely after I transfer touch2 or raise contact 2, the touchesEnded methodology similar to touch1 shall be referred to as, that’s, the pad similar to touch1 shall be darkened and the corresponding callback operate shall be referred to as.
It is a very difficult drawback as a result of it significantly impacts my app expertise. It’s price noting that this drawback solely happens with two touches, and doesn’t happen with every other variety of touches. That’s to say, when my display has many touches and the corresponding pads are lit on the identical time, transferring or lifting any one of many touches can work usually. This drawback solely happens when two touches exist on the display on the identical time and each touches are touched in a static method (that’s, touchesMoved will not be triggered). If touch1 or touch2 strikes, the operate will work usually.
Code framework
And the code framework is as follows:not all codes
class MultiPadUIView: UIView {
// ViewModel reference
// Replace utilizing mix
// Callback closure,
var functionTouchesBegin (()->Void)
var functionTouchesEnded (()->Void)
// Contact and monitoring mapping, Thread Security
// personal let stateQueue = DispatchQueue(label: "com.youapp.touchQueue",
// qos: .userInteractive,
// attributes: .concurrent)
personal var touchStatus : [Int]
override init(body: CGRect) {
tremendous.init(body: body)
self.isMultipleTouchEnabled = true
self.backgroundColor = .systemBackground
self.layer.cornerRadius = 12
}
required init?(coder: NSCoder) {
tremendous.init(coder: coder)
self.isMultipleTouchEnabled = true
backgroundColor = .clear
}
// Invalidate the static picture cache, and set wants format
personal func invalidateCache() {
cachedImage = nil
resetTouchStates()
setNeedsLayout()
}
personal var padFrames: [CGRect] = []
personal var cachedImage: UIImage?
personal func resetTouchStates() {
}
personal func calculatePadFrames() {
}
override func draw(_ rect: CGRect) {
tremendous.draw(rect)
if cachedImage == nil {
cachedImage = generateStaticImage()
}
cachedImage?.draw(in: bounds)
drawDynamicFeedback()
}
personal func generateStaticImage() -> UIImage?
}
// draw dynamic content material based on touchStatus
personal func drawDynamicFeedback()
}
// Known as after setNeedDisplay and each contact on display, referred to as continuously
override func layoutSubviews() {
tremendous.layoutSubviews()
resetTouchStates()
setNeedsDisplay()
}
override func touchesBegan(_ touches: Set, with occasion: UIEvent?) {
for contact in touches {
// some updataTouchStatus logic,
if let newIndex = newIndex {
//callback operate
functionTouchesBegin?(newIndex)
updateTouchState(oldIndex: nil, newIndex: newIndex)
}
}
// mark the view should be redrawn, and replace dynamic content material based on contact standing
setNeedsDisplay()
}
override func touchesEnded(_ touches: Set, with occasion: UIEvent?) {
for contact in touches {
// updataTouchesLogic
// callback
if some situation {
// touches ended closure
functionTouchesBegin?(newIndex)
}
}
// mark the view should be redrawn, and replace dynamic content material based on contact standing
setNeedsDisplay()
}
override func touchesMoved(_ touches: Set, with occasion: UIEvent?) {
// some logic
// mark the view should be redrawn, and replace dynamic content material based on contact standing
setNeedsDisplay()
}
override func touchesCancelled(_ touches: Set, with occasion: UIEvent?) {
touchesEnded(touches, with: occasion)
resetTouchStates()
}
}
After asking the AI instrument, it stated that the attainable motive was thread blocking. I used a thread-safe information construction because the implementation of my contact standing, but it surely nonetheless didn’t work correctly.
And after my debugging, after I saved touch2 nonetheless and lifted touch1, this system didn’t enter touchesEnded() in any respect. Solely after transferring touch2 will the touchesEnded() similar to lifting touch1 be triggered.