diff --git a/HostApp/HostApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/HostApp/HostApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index a6ccbdc..ac1d907 100644 --- a/HostApp/HostApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/HostApp/HostApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/aws-amplify/amplify-swift", "state" : { - "revision" : "c5a33cad99211150814183a2242d182dfd28fa2a", - "version" : "2.51.2" + "branch" : "fix/liveness-memory-leaks", + "revision" : "130f41521b43e4c92bc660ad6d145b8379aa4918" } }, { @@ -104,8 +104,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-asn1.git", "state" : { - "revision" : "f70225981241859eb4aa1a18a75531d26637c8cc", - "version" : "1.4.0" + "revision" : "40d25bbb2fc5b557a9aa8512210bded327c0f60d", + "version" : "1.5.0" } }, { @@ -131,8 +131,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-certificates.git", "state" : { - "revision" : "4b092f15164144c24554e0a75e080a960c5190a6", - "version" : "1.14.0" + "revision" : "c399f90e7bbe8874f6cbfda1d5f9023d1f5ce122", + "version" : "1.15.1" } }, { @@ -149,8 +149,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-crypto.git", "state" : { - "revision" : "95ba0316a9b733e92bb6b071255ff46263bbe7dc", - "version" : "3.15.1" + "revision" : "e8ed8867ec23bccf5f3bb9342148fa8deaff9b49", + "version" : "4.1.0" } }, { @@ -158,8 +158,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-http-structured-headers.git", "state" : { - "revision" : "1625f271afb04375bf48737a5572613248d0e7a0", - "version" : "1.4.0" + "revision" : "a9f3c352f4d46afd155e00b3c6e85decae6bcbeb", + "version" : "1.5.0" } }, { @@ -167,8 +167,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-http-types.git", "state" : { - "revision" : "a0a57e949a8903563aba4615869310c0ebf14c03", - "version" : "1.4.0" + "revision" : "45eb0224913ea070ec4fba17291b9e7ecf4749ca", + "version" : "1.5.1" } }, { @@ -194,8 +194,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio.git", "state" : { - "revision" : "a18bddb0acf7a40d982b2f128ce73ce4ee31f352", - "version" : "2.86.2" + "revision" : "a24771a4c228ff116df343c85fcf3dcfae31a06c", + "version" : "2.88.0" } }, { @@ -203,8 +203,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-extras.git", "state" : { - "revision" : "a55c3dd3a81d035af8a20ce5718889c0dcab073d", - "version" : "1.29.0" + "revision" : "7ee281d816fa8e5f3967a2c294035a318ea551c7", + "version" : "1.31.0" } }, { @@ -221,8 +221,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-ssl.git", "state" : { - "revision" : "b2b043a8810ab6d51b3ff4df17f057d87ef1ec7c", - "version" : "2.34.1" + "revision" : "173cc69a058623525a58ae6710e2f5727c663793", + "version" : "2.36.0" } }, { @@ -248,8 +248,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-protobuf.git", "state" : { - "revision" : "c6fe6442e6a64250495669325044052e113e990c", - "version" : "1.32.0" + "revision" : "c169a5744230951031770e27e475ff6eefe51f9d", + "version" : "1.33.3" } }, { @@ -257,8 +257,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swift-server/swift-service-lifecycle.git", "state" : { - "revision" : "0fcc4c9c2d58dd98504c06f7308c86de775396ff", - "version" : "2.9.0" + "revision" : "1de37290c0ab3c5a96028e0f02911b672fd42348", + "version" : "2.9.1" } }, { diff --git a/Package.resolved b/Package.resolved index a6ccbdc..ac1d907 100644 --- a/Package.resolved +++ b/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/aws-amplify/amplify-swift", "state" : { - "revision" : "c5a33cad99211150814183a2242d182dfd28fa2a", - "version" : "2.51.2" + "branch" : "fix/liveness-memory-leaks", + "revision" : "130f41521b43e4c92bc660ad6d145b8379aa4918" } }, { @@ -104,8 +104,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-asn1.git", "state" : { - "revision" : "f70225981241859eb4aa1a18a75531d26637c8cc", - "version" : "1.4.0" + "revision" : "40d25bbb2fc5b557a9aa8512210bded327c0f60d", + "version" : "1.5.0" } }, { @@ -131,8 +131,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-certificates.git", "state" : { - "revision" : "4b092f15164144c24554e0a75e080a960c5190a6", - "version" : "1.14.0" + "revision" : "c399f90e7bbe8874f6cbfda1d5f9023d1f5ce122", + "version" : "1.15.1" } }, { @@ -149,8 +149,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-crypto.git", "state" : { - "revision" : "95ba0316a9b733e92bb6b071255ff46263bbe7dc", - "version" : "3.15.1" + "revision" : "e8ed8867ec23bccf5f3bb9342148fa8deaff9b49", + "version" : "4.1.0" } }, { @@ -158,8 +158,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-http-structured-headers.git", "state" : { - "revision" : "1625f271afb04375bf48737a5572613248d0e7a0", - "version" : "1.4.0" + "revision" : "a9f3c352f4d46afd155e00b3c6e85decae6bcbeb", + "version" : "1.5.0" } }, { @@ -167,8 +167,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-http-types.git", "state" : { - "revision" : "a0a57e949a8903563aba4615869310c0ebf14c03", - "version" : "1.4.0" + "revision" : "45eb0224913ea070ec4fba17291b9e7ecf4749ca", + "version" : "1.5.1" } }, { @@ -194,8 +194,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio.git", "state" : { - "revision" : "a18bddb0acf7a40d982b2f128ce73ce4ee31f352", - "version" : "2.86.2" + "revision" : "a24771a4c228ff116df343c85fcf3dcfae31a06c", + "version" : "2.88.0" } }, { @@ -203,8 +203,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-extras.git", "state" : { - "revision" : "a55c3dd3a81d035af8a20ce5718889c0dcab073d", - "version" : "1.29.0" + "revision" : "7ee281d816fa8e5f3967a2c294035a318ea551c7", + "version" : "1.31.0" } }, { @@ -221,8 +221,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-ssl.git", "state" : { - "revision" : "b2b043a8810ab6d51b3ff4df17f057d87ef1ec7c", - "version" : "2.34.1" + "revision" : "173cc69a058623525a58ae6710e2f5727c663793", + "version" : "2.36.0" } }, { @@ -248,8 +248,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-protobuf.git", "state" : { - "revision" : "c6fe6442e6a64250495669325044052e113e990c", - "version" : "1.32.0" + "revision" : "c169a5744230951031770e27e475ff6eefe51f9d", + "version" : "1.33.3" } }, { @@ -257,8 +257,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swift-server/swift-service-lifecycle.git", "state" : { - "revision" : "0fcc4c9c2d58dd98504c06f7308c86de775396ff", - "version" : "2.9.0" + "revision" : "1de37290c0ab3c5a96028e0f02911b672fd42348", + "version" : "2.9.1" } }, { diff --git a/Package.swift b/Package.swift index 298149e..0612964 100644 --- a/Package.swift +++ b/Package.swift @@ -13,7 +13,7 @@ let package = Package( targets: ["FaceLiveness"]), ], dependencies: [ - .package(url: "https://github.com/aws-amplify/amplify-swift", from: "2.51.2") + .package(url: "https://github.com/aws-amplify/amplify-swift", branch: "fix/liveness-memory-leaks") ], targets: [ .target( diff --git a/Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionViewModel+VideoSegmentProcessor.swift b/Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionViewModel+VideoSegmentProcessor.swift index d2f8834..96b1cae 100644 --- a/Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionViewModel+VideoSegmentProcessor.swift +++ b/Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionViewModel+VideoSegmentProcessor.swift @@ -13,8 +13,8 @@ extension FaceLivenessDetectionViewModel: VideoSegmentProcessor { sendVideoEvent(data: chunk, videoEventTime: .zero) if !hasSentFinalVideoEvent && (livenessState.state == .completedDisplayingFreshness || livenessState.state == .completedNoLightCheck) { - DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + 0.9) { - self.sendFinalVideoEvent() + DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + 0.9) { [weak self] in + self?.sendFinalVideoEvent() } } } diff --git a/Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionViewModel.swift b/Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionViewModel.swift index 21ad7f6..98447b4 100644 --- a/Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionViewModel.swift +++ b/Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionViewModel.swift @@ -143,9 +143,9 @@ class FaceLivenessDetectionViewModel: ObservableObject { @objc func willResignActive(_ notification: Notification) { guard self.livenessState.state != .initial else { return } - DispatchQueue.main.async { - self.stopRecording() - self.livenessState.unrecoverableStateEncountered(.viewResignation) + DispatchQueue.main.async { [weak self] in + self?.stopRecording() + self?.livenessState.unrecoverableStateEncountered(.viewResignation) } } @@ -160,12 +160,13 @@ class FaceLivenessDetectionViewModel: ObservableObject { func configureCamera(withinFrame frame: CGRect) -> CALayer? { do { let avLayer = try captureSession?.configureCamera(frame: frame) - DispatchQueue.main.async { - self.livenessState.checkIsFacePrepared() + DispatchQueue.main.async { [weak self] in + self?.livenessState.checkIsFacePrepared() } return avLayer } catch { - DispatchQueue.main.async { + DispatchQueue.main.async { [weak self] in + guard let self else { return } self.livenessState.unrecoverableStateEncountered( self.generateLivenessError(from: error) ) @@ -203,8 +204,8 @@ class FaceLivenessDetectionViewModel: ObservableObject { ) livenessViewControllerDelegate?.drawOvalInCanvas(normalizedOvalRect) - DispatchQueue.main.async { - self.livenessState.ovalDisplayed() + DispatchQueue.main.async { [weak self] in + self?.livenessState.ovalDisplayed() onComplete() } ovalRect = normalizedOvalRect @@ -230,8 +231,8 @@ class FaceLivenessDetectionViewModel: ObservableObject { preCheckViewEnabled: isPreviewScreenEnabled) ) } catch { - DispatchQueue.main.async { - self.livenessState.unrecoverableStateEncountered(.couldNotOpenStream) + DispatchQueue.main.async { [weak self] in + self?.livenessState.unrecoverableStateEncountered(.couldNotOpenStream) } } } @@ -253,8 +254,8 @@ class FaceLivenessDetectionViewModel: ObservableObject { eventDate: { .init() } ) } catch { - DispatchQueue.main.async { - self.livenessState.unrecoverableStateEncountered(.unknown) + DispatchQueue.main.async { [weak self] in + self?.livenessState.unrecoverableStateEncountered(.unknown) } } } @@ -297,8 +298,8 @@ class FaceLivenessDetectionViewModel: ObservableObject { eventDate: { .init() } ) } catch { - DispatchQueue.main.async { - self.livenessState.unrecoverableStateEncountered(.unknown) + DispatchQueue.main.async { [weak self] in + self?.livenessState.unrecoverableStateEncountered(.unknown) } } } @@ -337,8 +338,8 @@ class FaceLivenessDetectionViewModel: ObservableObject { hasSentFinalVideoEvent = true } catch { - DispatchQueue.main.async { - self.livenessState.unrecoverableStateEncountered(.unknown) + DispatchQueue.main.async { [weak self] in + self?.livenessState.unrecoverableStateEncountered(.unknown) } } } @@ -355,14 +356,14 @@ class FaceLivenessDetectionViewModel: ObservableObject { } func handleFreshnessComplete() { - DispatchQueue.main.async { - self.livenessState.completedDisplayingFreshness() + DispatchQueue.main.async { [weak self] in + self?.livenessState.completedDisplayingFreshness() } } func completeNoLightCheck() { - DispatchQueue.main.async { - self.livenessState.completedNoLightCheck() + DispatchQueue.main.async { [weak self] in + self?.livenessState.completedNoLightCheck() } } @@ -379,8 +380,8 @@ class FaceLivenessDetectionViewModel: ObservableObject { eventDate: { eventDate } ) } catch { - DispatchQueue.main.async { - self.livenessState.unrecoverableStateEncountered(.unknown) + DispatchQueue.main.async { [weak self] in + self?.livenessState.unrecoverableStateEncountered(.unknown) } } } diff --git a/Sources/FaceLiveness/Views/Liveness/LivenessViewController.swift b/Sources/FaceLiveness/Views/Liveness/LivenessViewController.swift index 35952c1..96c3114 100644 --- a/Sources/FaceLiveness/Views/Liveness/LivenessViewController.swift +++ b/Sources/FaceLiveness/Views/Liveness/LivenessViewController.swift @@ -28,8 +28,6 @@ final class _LivenessViewController: UIViewController { self.viewModel = viewModel super.init(nibName: nil, bundle: nil) viewModel.livenessViewControllerDelegate = self - - viewModel.normalizeFace = { [weak self] face in guard let self = self else { return face } return DispatchQueue.main.sync { @@ -78,8 +76,8 @@ final class _LivenessViewController: UIViewController { let cameraFrame = CGRect(x: x, y: y, width: width, height: height) guard let avLayer = viewModel.configureCamera(withinFrame: cameraFrame) else { - DispatchQueue.main.async { - self.viewModel.livenessState + DispatchQueue.main.async { [weak self] in + self?.viewModel.livenessState .unrecoverableStateEncountered(.missingVideoPermission) } return @@ -91,7 +89,8 @@ final class _LivenessViewController: UIViewController { viewModel.cameraViewRect = previewLayer.frame } - DispatchQueue.main.async { + DispatchQueue.main.async { [weak self] in + guard let self else { return } self.view.layer.insertSublayer(avLayer, at: 0) self.view.layoutIfNeeded() @@ -117,7 +116,8 @@ final class _LivenessViewController: UIViewController { extension _LivenessViewController: FaceLivenessViewControllerPresenter { func displaySingleFrame(uiImage: UIImage) { - DispatchQueue.main.async { + DispatchQueue.main.async { [weak self] in + guard let self else { return } guard let previewLayer = self.previewLayer else { return } let imageView = UIImageView(image: uiImage) imageView.frame = previewLayer.frame @@ -130,8 +130,8 @@ extension _LivenessViewController: FaceLivenessViewControllerPresenter { func displayFreshness(colorSequences: [FaceLivenessSession.DisplayColor]) { self.ovalView?.setNeedsDisplay() - DispatchQueue.main.async { - self.viewModel.livenessState.displayingFreshness() + DispatchQueue.main.async { [weak self] in + self?.viewModel.livenessState.displayingFreshness() } self.freshness.showColorSequences( colorSequences, @@ -151,7 +151,8 @@ extension _LivenessViewController: FaceLivenessViewControllerPresenter { } func drawOvalInCanvas(_ ovalRect: CGRect) { - DispatchQueue.main.async { + DispatchQueue.main.async { [weak self] in + guard let self else { return } guard let previewLayer = self.previewLayer else { return } let ovalView = OvalView(