Updated iOS image classifier and object detector callback invocations to avoid retain cycles

This commit is contained in:
Prianka Liz Kariat 2023-05-03 14:29:33 +05:30
parent d9a245b80b
commit c82a27599b
2 changed files with 55 additions and 43 deletions

View File

@ -85,22 +85,34 @@ static NSString *const kTaskGraphName =
if (options.imageClassifierDelegate) { if (options.imageClassifierDelegate) {
_imageClassifierDelegate = options.imageClassifierDelegate; _imageClassifierDelegate = options.imageClassifierDelegate;
// Capturing `self` as weak in order to avoid `self` being kept in memory
// and cause a retain cycle, after self is set to `nil`.
MPPImageClassifier *__weak weakSelf = self;
dispatch_queue_t callbackQueue =
dispatch_queue_create("com.mediapipe.tasks.imageClassifierCallbackQueue", NULL);
packetsCallback = [=](absl::StatusOr<PacketMap> status_or_packets) { packetsCallback = [=](absl::StatusOr<PacketMap> status_or_packets) {
NSError *callbackError = nil; // Check to ensure that the delegate method is not called on a nil object
if (![MPPCommonUtils checkCppError:status_or_packets.status() toError:&callbackError]) { // leading to a segmentation fault, we check `weakSelf` is `nil` before
if ([_imageClassifierDelegate // performing any processing.
if (!weakSelf ||
![weakSelf.imageClassifierDelegate
respondsToSelector:@selector respondsToSelector:@selector
(imageClassifier: (imageClassifier:
didFinishClassificationWithResult:timestampInMilliseconds:error:)]) { didFinishClassificationWithResult:timestampInMilliseconds:error:)]) {
[_imageClassifierDelegate imageClassifier:self
didFinishClassificationWithResult:nil
timestampInMilliseconds:Timestamp::Unset().Value()
error:callbackError];
}
return; return;
} }
PacketMap &outputPacketMap = status_or_packets.value(); NSError *callbackError = nil;
if (![MPPCommonUtils checkCppError:status_or_packets.status() toError:&callbackError]) {
[weakSelf.imageClassifierDelegate imageClassifier:weakSelf
didFinishClassificationWithResult:nil
timestampInMilliseconds:Timestamp::Unset().Value()
error:callbackError];
return;
}
PacketMap outputPacketMap = status_or_packets.value();
if (outputPacketMap[kImageOutStreamName.cppString].IsEmpty()) { if (outputPacketMap[kImageOutStreamName.cppString].IsEmpty()) {
return; return;
} }
@ -109,18 +121,14 @@ static NSString *const kTaskGraphName =
[MPPImageClassifierResult imageClassifierResultWithClassificationsPacket: [MPPImageClassifierResult imageClassifierResultWithClassificationsPacket:
outputPacketMap[kClassificationsStreamName.cppString]]; outputPacketMap[kClassificationsStreamName.cppString]];
if ([_imageClassifierDelegate [weakSelf.imageClassifierDelegate
respondsToSelector:@selector imageClassifier:weakSelf
(imageClassifier:
didFinishClassificationWithResult:timestampInMilliseconds:error:)]) {
[_imageClassifierDelegate imageClassifier:self
didFinishClassificationWithResult:result didFinishClassificationWithResult:result
timestampInMilliseconds:outputPacketMap[kImageOutStreamName.cppString] timestampInMilliseconds:outputPacketMap[kImageOutStreamName.cppString]
.Timestamp() .Timestamp()
.Value() / .Value() /
kMicroSecondsPerMilliSecond kMicroSecondsPerMilliSecond
error:callbackError]; error:callbackError];
}
}; };
} }

View File

@ -81,17 +81,23 @@ static NSString *const kTaskGraphName = @"mediapipe.tasks.vision.ObjectDetectorG
if (options.objectDetectorDelegate) { if (options.objectDetectorDelegate) {
_objectDetectorDelegate = options.objectDetectorDelegate; _objectDetectorDelegate = options.objectDetectorDelegate;
// Capturing `self` as weak in order to avoid `self` being kept in memory
// and cause a retain cycle, after self is set to `nil`.
MPPObjectDetector *__weak weakSelf = self;
packetsCallback = [=](absl::StatusOr<PacketMap> statusOrPackets) { packetsCallback = [=](absl::StatusOr<PacketMap> statusOrPackets) {
NSError *callbackError = nil; if ([!weakSelf && weakSelf.objectDetectorDelegate
if (![MPPCommonUtils checkCppError:statusOrPackets.status() toError:&callbackError]) {
if ([_objectDetectorDelegate
respondsToSelector:@selector respondsToSelector:@selector
(objectDetector:didFinishDetectionWithResult:timestampInMilliseconds:error:)]) { (objectDetector:didFinishDetectionWithResult:timestampInMilliseconds:error:)]) {
[_objectDetectorDelegate objectDetector:self return;
}
NSError *callbackError = nil;
if (![MPPCommonUtils checkCppError:statusOrPackets.status() toError:&callbackError]) {
[_objectDetectorDelegate objectDetector:weakSelf
didFinishDetectionWithResult:nil didFinishDetectionWithResult:nil
timestampInMilliseconds:Timestamp::Unset().Value() timestampInMilliseconds:Timestamp::Unset().Value()
error:callbackError]; error:callbackError];
}
return; return;
} }
@ -103,17 +109,15 @@ static NSString *const kTaskGraphName = @"mediapipe.tasks.vision.ObjectDetectorG
MPPObjectDetectionResult *result = [MPPObjectDetectionResult MPPObjectDetectionResult *result = [MPPObjectDetectionResult
objectDetectionResultWithDetectionsPacket:statusOrPackets.value()[kDetectionsStreamName objectDetectionResultWithDetectionsPacket:statusOrPackets.value()[kDetectionsStreamName
.cppString]]; .cppString]];
if ([_objectDetectorDelegate
respondsToSelector:@selector [weakSelf.objectDetectorDelegate
(objectDetector:didFinishDetectionWithResult:timestampInMilliseconds:error:)]) { objectDetector:weakSelf
[_objectDetectorDelegate objectDetector:self
didFinishDetectionWithResult:result didFinishDetectionWithResult:result
timestampInMilliseconds:outputPacketMap[kImageOutStreamName.cppString] timestampInMilliseconds:outputPacketMap[kImageOutStreamName.cppString]
.Timestamp() .Timestamp()
.Value() / .Value() /
kMicroSecondsPerMilliSecond kMicroSecondsPerMilliSecond
error:callbackError]; error:callbackError];
}
}; };
} }