[ios] Fix place page memory leaks

Signed-off-by: Kiryl Kaveryn <kirylkaveryn@gmail.com>
This commit is contained in:
Kiryl Kaveryn
2025-08-19 14:27:16 +04:00
committed by Konstantin Pastbin
parent 1b04524d68
commit 6cccd32166
6 changed files with 55 additions and 50 deletions

View File

@@ -26,8 +26,8 @@ fileprivate struct DescriptionsViewModel {
final class ElevationProfilePresenter: NSObject { final class ElevationProfilePresenter: NSObject {
private weak var view: ElevationProfileViewProtocol? private weak var view: ElevationProfileViewProtocol?
private var trackData: PlacePageTrackData private weak var trackData: PlacePageTrackData?
private let delegate: ElevationProfileViewControllerDelegate? private weak var delegate: ElevationProfileViewControllerDelegate?
private let bookmarkManager: BookmarksManager = .shared() private let bookmarkManager: BookmarksManager = .shared()
private let cellSpacing: CGFloat = 8 private let cellSpacing: CGFloat = 8
@@ -85,7 +85,8 @@ extension ElevationProfilePresenter: ElevationProfilePresenterProtocol {
view?.isChartViewHidden = false view?.isChartViewHidden = false
let kMinPointsToDraw = 2 let kMinPointsToDraw = 2
guard let profileData = trackData.elevationProfileData, guard let trackData = trackData,
let profileData = trackData.elevationProfileData,
let chartData, let chartData,
chartData.points.count >= kMinPointsToDraw else { chartData.points.count >= kMinPointsToDraw else {
view?.userInteractionEnabled = false view?.userInteractionEnabled = false

View File

@@ -1270,7 +1270,7 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="72"/> <rect key="frame" x="0.0" y="0.0" width="375" height="72"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="spW-XI-KSY" customClass="PlacePageHeaderView" customModule="CoMaps" customModuleProvider="target"> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="spW-XI-KSY">
<rect key="frame" x="0.0" y="62" width="375" height="10"/> <rect key="frame" x="0.0" y="62" width="375" height="10"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/> <color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints> <constraints>
@@ -1280,7 +1280,7 @@
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="PPNavigationShadowView"/> <userDefinedRuntimeAttribute type="string" keyPath="styleName" value="PPNavigationShadowView"/>
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</view> </view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fqh-H3-eji" customClass="PlacePageHeaderView" customModule="CoMaps" customModuleProvider="target"> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fqh-H3-eji">
<rect key="frame" x="0.0" y="20" width="375" height="52"/> <rect key="frame" x="0.0" y="20" width="375" height="52"/>
<subviews> <subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Gdy-g5-gbM"> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Gdy-g5-gbM">
@@ -1405,13 +1405,13 @@
<image name="ic_arrow_gray_down" width="28" height="28"/> <image name="ic_arrow_gray_down" width="28" height="28"/>
<image name="ic_placepage_open_hours" width="28" height="28"/> <image name="ic_placepage_open_hours" width="28" height="28"/>
<systemColor name="separatorColor"> <systemColor name="separatorColor">
<color red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.28999999999999998" colorSpace="custom" customColorSpace="sRGB"/> <color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.28999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor> </systemColor>
<systemColor name="systemBackgroundColor"> <systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor> </systemColor>
<systemColor name="systemRedColor"> <systemColor name="systemRedColor">
<color red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color red="1" green="0.23137254901960785" blue="0.18823529411764706" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor> </systemColor>
</resources> </resources>
</document> </document>

View File

@@ -1,81 +1,81 @@
class PlacePageCommonLayout: NSObject, IPlacePageLayout { class PlacePageCommonLayout: NSObject, IPlacePageLayout {
private let distanceFormatter = DistanceFormatter.self private let distanceFormatter = DistanceFormatter.self
private let altitudeFormatter = AltitudeFormatter.self private let altitudeFormatter = AltitudeFormatter.self
private var placePageData: PlacePageData private var placePageData: PlacePageData
private var interactor: PlacePageInteractor private var interactor: PlacePageInteractor
private let storyboard: UIStoryboard private let storyboard: UIStoryboard
private var lastLocation: CLLocation?
weak var presenter: PlacePagePresenterProtocol? weak var presenter: PlacePagePresenterProtocol?
fileprivate var lastLocation: CLLocation? var headerViewControllers: [UIViewController] {
lazy var headerViewControllers: [UIViewController] = {
[headerViewController, previewViewController] [headerViewController, previewViewController]
}() }
lazy var bodyViewControllers: [UIViewController] = { lazy var bodyViewControllers: [UIViewController] = {
return configureViewControllers() configureViewControllers()
}() }()
var actionBar: ActionBarViewController? { var actionBar: ActionBarViewController? {
return actionBarViewController actionBarViewController
} }
var navigationBar: UIViewController? { var navigationBar: UIViewController? {
return placePageNavigationViewController placePageNavigationViewController
} }
lazy var headerViewController: PlacePageHeaderViewController = { lazy var headerViewController: PlacePageHeaderViewController = {
PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .flexible) PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .flexible)
}() }()
lazy var previewViewController: PlacePagePreviewViewController = { private lazy var previewViewController: PlacePagePreviewViewController = {
let vc = storyboard.instantiateViewController(ofType: PlacePagePreviewViewController.self) let vc = storyboard.instantiateViewController(ofType: PlacePagePreviewViewController.self)
vc.placePagePreviewData = placePageData.previewData vc.placePagePreviewData = placePageData.previewData
return vc return vc
} () }()
lazy var wikiDescriptionViewController: WikiDescriptionViewController = { private lazy var wikiDescriptionViewController: WikiDescriptionViewController = {
let vc = storyboard.instantiateViewController(ofType: WikiDescriptionViewController.self) let vc = storyboard.instantiateViewController(ofType: WikiDescriptionViewController.self)
vc.view.isHidden = true vc.view.isHidden = true
vc.delegate = interactor vc.delegate = interactor
return vc return vc
} () }()
lazy var editBookmarkViewController: PlacePageEditBookmarkOrTrackViewController = { private lazy var editBookmarkViewController: PlacePageEditBookmarkOrTrackViewController = {
let vc = storyboard.instantiateViewController(ofType: PlacePageEditBookmarkOrTrackViewController.self) let vc = storyboard.instantiateViewController(ofType: PlacePageEditBookmarkOrTrackViewController.self)
vc.view.isHidden = true vc.view.isHidden = true
vc.delegate = interactor vc.delegate = interactor
return vc return vc
} () }()
lazy var infoViewController: PlacePageInfoViewController = { private lazy var infoViewController: PlacePageInfoViewController = {
let vc = storyboard.instantiateViewController(ofType: PlacePageInfoViewController.self) let vc = storyboard.instantiateViewController(ofType: PlacePageInfoViewController.self)
vc.placePageInfoData = placePageData.infoData vc.placePageInfoData = placePageData.infoData
vc.delegate = interactor vc.delegate = interactor
return vc return vc
} () }()
lazy var buttonsViewController: PlacePageButtonsViewController = { private lazy var buttonsViewController: PlacePageButtonsViewController = {
let vc = storyboard.instantiateViewController(ofType: PlacePageButtonsViewController.self) let vc = storyboard.instantiateViewController(ofType: PlacePageButtonsViewController.self)
vc.buttonsData = placePageData.buttonsData! vc.buttonsData = placePageData.buttonsData!
vc.delegate = interactor vc.delegate = interactor
return vc return vc
} () }()
lazy var actionBarViewController: ActionBarViewController = { private lazy var actionBarViewController: ActionBarViewController = {
let vc = storyboard.instantiateViewController(ofType: ActionBarViewController.self) let vc = storyboard.instantiateViewController(ofType: ActionBarViewController.self)
vc.placePageData = placePageData vc.placePageData = placePageData
vc.canAddStop = MWMRouter.canAddIntermediatePoint() vc.canAddStop = MWMRouter.canAddIntermediatePoint()
vc.isRoutePlanning = MWMNavigationDashboardManager.shared().state != .hidden vc.isRoutePlanning = MWMNavigationDashboardManager.shared().state != .hidden
vc.delegate = interactor vc.delegate = interactor
return vc return vc
} () }()
lazy var placePageNavigationViewController: PlacePageHeaderViewController = { private lazy var placePageNavigationViewController: PlacePageHeaderViewController = {
return PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .fixed) return PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .fixed)
} () }()
init(interactor: PlacePageInteractor, storyboard: UIStoryboard, data: PlacePageData) { init(interactor: PlacePageInteractor, storyboard: UIStoryboard, data: PlacePageData) {
self.interactor = interactor self.interactor = interactor
@@ -163,7 +163,6 @@ class PlacePageCommonLayout: NSObject, IPlacePageLayout {
} }
} }
// MARK: - PlacePageData async callbacks for loaders // MARK: - PlacePageData async callbacks for loaders
extension PlacePageCommonLayout { extension PlacePageCommonLayout {

View File

@@ -17,25 +17,25 @@ class PlacePageTrackLayout: IPlacePageLayout {
placePageNavigationViewController placePageNavigationViewController
} }
lazy var headerViewControllers: [UIViewController] = { var headerViewControllers: [UIViewController] {
[headerViewController, previewViewController] [headerViewController, previewViewController]
}() }
lazy var headerViewController: PlacePageHeaderViewController = { lazy var headerViewController: PlacePageHeaderViewController = {
PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .flexible) PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .flexible)
}() }()
lazy var previewViewController: PlacePagePreviewViewController = { private lazy var previewViewController: PlacePagePreviewViewController = {
let vc = storyboard.instantiateViewController(ofType: PlacePagePreviewViewController.self) let vc = storyboard.instantiateViewController(ofType: PlacePagePreviewViewController.self)
vc.placePagePreviewData = placePageData.previewData vc.placePagePreviewData = placePageData.previewData
return vc return vc
}() }()
lazy var placePageNavigationViewController: PlacePageHeaderViewController = { private lazy var placePageNavigationViewController: PlacePageHeaderViewController = {
return PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .fixed) return PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .fixed)
}() }()
lazy var editTrackViewController: PlacePageEditBookmarkOrTrackViewController = { private lazy var editTrackViewController: PlacePageEditBookmarkOrTrackViewController = {
let vc = storyboard.instantiateViewController(ofType: PlacePageEditBookmarkOrTrackViewController.self) let vc = storyboard.instantiateViewController(ofType: PlacePageEditBookmarkOrTrackViewController.self)
vc.view.isHidden = true vc.view.isHidden = true
vc.delegate = interactor vc.delegate = interactor
@@ -49,7 +49,7 @@ class PlacePageTrackLayout: IPlacePageLayout {
return ElevationProfileBuilder.build(trackData: trackData, delegate: interactor) return ElevationProfileBuilder.build(trackData: trackData, delegate: interactor)
}() }()
lazy var actionBarViewController: ActionBarViewController = { private lazy var actionBarViewController: ActionBarViewController = {
let vc = storyboard.instantiateViewController(ofType: ActionBarViewController.self) let vc = storyboard.instantiateViewController(ofType: ActionBarViewController.self)
vc.placePageData = placePageData vc.placePageData = placePageData
vc.canAddStop = MWMRouter.canAddIntermediatePoint() vc.canAddStop = MWMRouter.canAddIntermediatePoint()

View File

@@ -5,7 +5,7 @@ final class PlacePageTrackRecordingLayout: IPlacePageLayout {
weak var presenter: PlacePagePresenterProtocol? weak var presenter: PlacePagePresenterProtocol?
lazy var bodyViewControllers: [UIViewController] = { lazy var bodyViewControllers: [UIViewController] = {
return configureViewControllers() configureViewControllers()
}() }()
var actionBar: ActionBarViewController? { var actionBar: ActionBarViewController? {
@@ -16,19 +16,19 @@ final class PlacePageTrackRecordingLayout: IPlacePageLayout {
placePageNavigationViewController placePageNavigationViewController
} }
lazy var headerViewControllers: [UIViewController] = { var headerViewControllers: [UIViewController] {
[headerViewController] [headerViewController]
}() }
lazy var headerViewController: PlacePageHeaderViewController = { lazy var headerViewController: PlacePageHeaderViewController = {
return PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .flexible) PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .flexible)
}() }()
lazy var placePageNavigationViewController: PlacePageHeaderViewController = { private lazy var placePageNavigationViewController: PlacePageHeaderViewController = {
return PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .fixed) PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .fixed)
}() }()
lazy var elevationProfileViewController: ElevationProfileViewController? = { private lazy var elevationProfileViewController: ElevationProfileViewController? = {
guard let trackData = placePageData.trackData else { guard let trackData = placePageData.trackData else {
return nil return nil
} }
@@ -36,7 +36,7 @@ final class PlacePageTrackRecordingLayout: IPlacePageLayout {
delegate: interactor) delegate: interactor)
}() }()
lazy var actionBarViewController: ActionBarViewController = { private lazy var actionBarViewController: ActionBarViewController = {
let vc = storyboard.instantiateViewController(ofType: ActionBarViewController.self) let vc = storyboard.instantiateViewController(ofType: ActionBarViewController.self)
vc.placePageData = placePageData vc.placePageData = placePageData
vc.canAddStop = MWMRouter.canAddIntermediatePoint() vc.canAddStop = MWMRouter.canAddIntermediatePoint()

View File

@@ -1,5 +1,5 @@
protocol PlacePageViewProtocol: AnyObject { protocol PlacePageViewProtocol: AnyObject {
var interactor: PlacePageInteractorProtocol! { get set } var interactor: PlacePageInteractorProtocol? { get set }
func setLayout(_ layout: IPlacePageLayout) func setLayout(_ layout: IPlacePageLayout)
func closeAnimated(completion: (() -> Void)?) func closeAnimated(completion: (() -> Void)?)
@@ -35,7 +35,7 @@ final class PlacePageScrollView: UIScrollView {
stackView.distribution = .fill stackView.distribution = .fill
return stackView return stackView
}() }()
var interactor: PlacePageInteractorProtocol! var interactor: PlacePageInteractorProtocol?
var beginDragging = false var beginDragging = false
var rootViewController: MapViewController { var rootViewController: MapViewController {
MapViewController.shared()! MapViewController.shared()!
@@ -220,8 +220,13 @@ final class PlacePageScrollView: UIScrollView {
} }
private func cleanupLayout() { private func cleanupLayout() {
layout?.actionBar?.view.removeFromSuperview() guard let layout else { return }
layout?.navigationBar?.view.removeFromSuperview() let childViewControllers = [layout.actionBar, layout.navigationBar] + layout.headerViewControllers + layout.bodyViewControllers
childViewControllers.forEach {
$0?.willMove(toParent: nil)
$0?.view.removeFromSuperview()
$0?.removeFromParent()
}
headerStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } headerStackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
stackView.arrangedSubviews.forEach { $0.removeFromSuperview() } stackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
} }
@@ -293,7 +298,7 @@ final class PlacePageScrollView: UIScrollView {
private func updateTopBound(_ bound: CGFloat, duration: TimeInterval) { private func updateTopBound(_ bound: CGFloat, duration: TimeInterval) {
alternativeSizeClass(iPhone: { alternativeSizeClass(iPhone: {
interactor.updateTopBound(bound, duration: duration) interactor?.updateTopBound(bound, duration: duration)
}, iPad: {}) }, iPad: {})
} }
} }