I'm writing a Qt app on iOS which uses the MLKit FaceDetector. I have a FaceDetector class which has the following method:
void FaceDetector::runFaceDetection(const QImage &image)
{
// initialize a MLKFaceDetector
[mlkFaceDetector processImage:visionImage
completion:^(NSArray<MLKFace *> *_Nullable faces, NSError *_Nullable error) {
if (error != nil) {
// process error
}
DetectionResults results; // DetectionResults is just another of my classes
// process results using faces
setResults(results);
emit detectionComplete(true);
}];
}
where setResults and detectionComplete are other member function of the FaceDetector
I use the FaceDetector in a FaceDetectionFilter class:
FaceDetectionFilter.h
class FaceDetectionFilter : public QAbstractVideoFilter {
private:
FaceDetector m_FaceDetector;
}
Basically I use the FaceDetectionFilter in my QML with Camera and VideoOutput component, and the VideoOutput is able to detect faces, so far so good.
However, the app occasionally crashes when I close my camera page while the filter is running, i.e. the page is popped out of the app's stackview. XCode shows EXC_BAD_ACCESS error in the setResults or detectionComplete line in the runFaceDetection method.
I think this is due to when the camera page is popped, the FaceDetectionFilter and thus the FaceDetector object is destroyed. But once in a while the completion handler callback is executed after the object destruction, resulting in illegal memory access.
I tried to fix this by adding a m_Initialized boolean member to the FaceDetector class, and setting it to false in the destructor:
FaceDetector ::~FaceDetector ()
{
m_Initialized = false;
}
and in the runFaceDetection method:
void FaceDetector::runFaceDetection(const QImage &image)
{
// initialize a MLKFaceDetector
[mlkFaceDetector processImage:visionImage
completion:^(NSArray<MLKFace *> *_Nullable faces, NSError *_Nullable error) {
if (!m_Initialized) {
qDebug() << "FaceDetector destroyed, stop processing";
return;
}
if (error != nil) {
// process error
}
// continue processing
}];
}
This seems to fix the crash, and I can see that when I close the camera, occasionally the "stop processing" line is printed.
However, very rarely the app still crashes and it seems the m_Initialized guard is not working (but I've only been able to reproduce this once, it's so rare that I'm not even sure if that really happened). I think this rare case occurs when the FaceDetector destruction happens between the m_Initialized guard and the setResults line, therefore making the guard check fail.
My question is: are there any other better way to solve this issue? I've searched online for a while and found some answers from the Objective C side related to the use of __block or the concept of "retain" the object. Or, from C++ side the use of shared_ptr to manage object lifetime. I guess the key is find a way to know if the object itself is destroyed in the completion handler, or am I missing something?