Skip to content

Commit ffee56f

Browse files
authored
Merge pull request #99 from tappeddev/fix-memory-leak
fix-memory-leak (iOS)
2 parents 6503289 + 2c02217 commit ffee56f

File tree

4 files changed

+96
-57
lines changed

4 files changed

+96
-57
lines changed

arcgis_map_sdk_ios/ios/arcgis_map_sdk_ios/Sources/arcgis_map_sdk_ios/ArcgisMapPlugin.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,4 @@ public class ArcgisMapPlugin: NSObject, FlutterPlugin {
1313
)
1414
registrar.addMethodCallDelegate(instance, channel: channel)
1515
}
16-
1716
}

arcgis_map_sdk_ios/ios/arcgis_map_sdk_ios/Sources/arcgis_map_sdk_ios/ArcgisMapView.swift

Lines changed: 88 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,14 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
110110
}
111111

112112
private func setupMethodChannel() {
113-
methodChannel.setMethodCallHandler({ [self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
114-
switch (call.method) {
113+
methodChannel.setMethodCallHandler({
114+
[weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
115+
guard let self = self else {
116+
result(FlutterError(code: "disposed", message: "View was disposed", details: nil))
117+
return
118+
}
119+
120+
switch call.method {
115121
case "on_init_complete": waitForViewToInit(call, result)
116122
case "zoom_in": onZoomIn(call, result)
117123
case "zoom_out": onZoomOut(call, result)
@@ -146,17 +152,18 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
146152

147153
private func waitForViewToInit(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
148154
if mapContentView.viewModel.mapViewProxy != nil {
149-
result(true)
155+
result(true)
150156
} else {
151-
mapContentView.viewModel.onViewInit = { [weak self] in
157+
mapContentView.viewModel.onViewInit = { [weak vm = mapContentView.viewModel] in
152158
result(true)
159+
vm?.onViewInit = nil
153160
}
154161
}
155162
}
156163

157164
private func onZoomIn(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
158-
let currentScale = mapContentView.viewModel.viewpoint.targetScale
159-
165+
let currentScale = mapContentView.viewModel.viewpoint.targetScale
166+
160167
guard let args = call.arguments as? [String: Any] else {
161168
result(FlutterError(code: "missing_data", message: "Invalid arguments", details: nil))
162169
return
@@ -176,9 +183,10 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
176183
}
177184
}
178185
let newScale = ArcgisMapView.convertZoomLevelToMapScale(totalZoomLevel)
179-
Task {
186+
Task { [weak self] in
187+
guard let self = self else { return }
180188
do {
181-
await mapContentView.viewModel.mapViewProxy?.setViewpointScale(newScale)
189+
await self.mapContentView.viewModel.mapViewProxy?.setViewpointScale(newScale)
182190
result(true)
183191
}
184192
}
@@ -206,20 +214,23 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
206214
}
207215
}
208216
let newScale = ArcgisMapView.convertZoomLevelToMapScale(totalZoomLevel)
209-
Task {
217+
Task { [weak self] in
218+
guard let self = self else { return }
210219
do {
211-
let success = await mapContentView.viewModel.mapViewProxy?.setViewpointScale(newScale)
220+
let success = await self.mapContentView.viewModel.mapViewProxy?.setViewpointScale(
221+
newScale)
212222
result(success)
213223
}
214224
}
215225
}
216-
217-
private func onRotate(_ call: FlutterMethodCall, _ result:@escaping FlutterResult) {
226+
227+
private func onRotate(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
218228
guard let angleDouble = call.arguments as? Double else {
219229
result(FlutterError(code: "missing_data", message: "Invalid arguments", details: nil))
220230
return
221231
}
222-
Task {
232+
Task { [weak self] in
233+
guard let self = self else { return }
223234
do {
224235
let success = await mapContentView.viewModel.mapViewProxy?.setViewpointRotation(angleDouble)
225236
result(success)
@@ -254,7 +265,8 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
254265
result(FlutterError(code: "missing_data", message: "Invalid arguments", details: nil))
255266
return
256267
}
257-
Task {
268+
Task { [weak self] in
269+
guard let self = self else { return }
258270
do {
259271
let point: LatLng = try JsonUtil.objectOfJson(args["point"] as! Dictionary<String, Any>)
260272
let zoomLevel = args["zoomLevel"] as? Int
@@ -266,9 +278,9 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
266278
if let zoomLevel = zoomLevel {
267279
scale = ArcgisMapView.convertZoomLevelToMapScale(zoomLevel)
268280
} else {
269-
scale = mapContentView.viewModel.viewpoint.targetScale
281+
scale = self.mapContentView.viewModel.viewpoint.targetScale
270282
}
271-
let success = await mapContentView.viewModel.mapViewProxy?.setViewpoint(
283+
let success = await self.mapContentView.viewModel.mapViewProxy?.setViewpoint(
272284
Viewpoint(center: point.toAGSPoint(), scale: scale),
273285
duration: (animationOptions?.duration ?? 0) / 1000
274286
)
@@ -287,9 +299,12 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
287299
Task {
288300
do {
289301
let payload: MoveToPointsPayload = try JsonUtil.objectOfJson(args)
290-
let polyline = Polyline(points: payload.points.map { latLng in Point(x: latLng.longitude, y:latLng.latitude, spatialReference: .wgs84) })
291-
292-
if(payload.padding != nil) {
302+
let polyline = Polyline(
303+
points: payload.points.map { latLng in
304+
Point(x: latLng.longitude, y: latLng.latitude, spatialReference: .wgs84)
305+
})
306+
307+
if payload.padding != nil {
293308
let success = try await mapContentView.viewModel.mapViewProxy!.setViewpointGeometry(polyline.extent, padding: payload.padding!)
294309
result(success)
295310
} else {
@@ -312,8 +327,9 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
312327
return
313328
}
314329

315-
316-
let existingIds = mapContentView.viewModel.defaultGraphicsOverlay.graphics.compactMap { object in
330+
331+
let existingIds = mapContentView.viewModel.defaultGraphicsOverlay.graphics.compactMap {
332+
object in
317333
let graphic = object as! Graphic
318334
return graphic.attributes["id"] as? String
319335
}
@@ -327,7 +343,7 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
327343
return existingIds.contains(id)
328344
})
329345

330-
if(hasExistingGraphics) {
346+
if hasExistingGraphics {
331347
result(false)
332348
return
333349
}
@@ -370,7 +386,8 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
370386
}
371387

372388
private func onRetryLoad(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
373-
Task {
389+
Task { [weak self] in
390+
guard let self = self else { return }
374391
do {
375392
try await mapContentView.viewModel.map.retryLoad()
376393
result(true)
@@ -430,9 +447,10 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
430447

431448

432449
private func onStartLocationDisplayDataSource(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
433-
Task {
450+
Task { [weak self] in
451+
guard let self = self else { return }
434452
do {
435-
try await mapContentView.viewModel.locationDisplay.dataSource.start();
453+
try await self.mapContentView.viewModel.locationDisplay.dataSource.start()
436454
result(true)
437455
}
438456
catch{
@@ -447,9 +465,10 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
447465
}
448466

449467
private func onStopLocationDisplayDataSource(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
450-
Task {
468+
Task { [weak self] in
469+
guard let self = self else { return }
451470
do {
452-
await mapContentView.viewModel.locationDisplay.dataSource.stop()
471+
await self.mapContentView.viewModel.locationDisplay.dataSource.stop()
453472
result(true)
454473
}
455474
}
@@ -568,18 +587,19 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
568587
}
569588

570589
private func onExportImage(_ result: @escaping FlutterResult) {
571-
Task {
572-
do {
573-
let image = try await mapContentView.viewModel.mapViewProxy!.exportImage()
574-
if let imageData = image.pngData() {
575-
result(FlutterStandardTypedData(bytes: imageData))
576-
} else {
577-
result(FlutterError(code: "conversion_error", message: "Failed to convert image to PNG data", details: nil))
578-
}
579-
} catch {
580-
result(FlutterError(code: "export_error", message: error.localizedDescription, details: nil))
581-
}
582-
}
590+
Task { [weak self] in
591+
guard let self = self else { return }
592+
do {
593+
let image = try await self.mapContentView.viewModel.mapViewProxy!.exportImage()
594+
if let imageData = image.pngData() {
595+
result(FlutterStandardTypedData(bytes: imageData))
596+
} else {
597+
result(FlutterError(code: "conversion_error", message: "Failed to convert image to PNG data", details: nil))
598+
}
599+
} catch {
600+
result(FlutterError(code: "export_error", message: error.localizedDescription, details: nil))
601+
}
602+
}
583603
}
584604

585605
private func operationWithSymbol(_ call: FlutterMethodCall, _ result: @escaping FlutterResult, handler: (Symbol) -> Void) {
@@ -591,11 +611,23 @@ class ArcgisMapView: NSObject, FlutterPlatformView {
591611
let symbol = try GraphicsParser(registrar: flutterPluginRegistrar).parseSymbol(args)
592612
handler(symbol)
593613
result(true)
594-
}
595-
catch {
614+
} catch {
596615
result(FlutterError(code: "unknown_error", message: "Error while adding graphic. \(error)", details: nil))
597616
}
598617
}
618+
619+
deinit {
620+
mapContentView.viewModel.onScaleChanged = nil
621+
mapContentView.viewModel.onVisibleAreaChanged = nil
622+
mapContentView.viewModel.onLoadStatusChanged = nil
623+
mapContentView.viewModel.onViewInit = nil
624+
mapContentView.viewModel.mapViewProxy = nil
625+
mapContentView.viewModel.stopLocationDataSource()
626+
627+
zoomEventChannel.setStreamHandler(nil)
628+
centerPositionEventChannel.setStreamHandler(nil)
629+
methodChannel.setMethodCallHandler(nil)
630+
}
599631
}
600632

601633
extension Basemap.Style: CaseIterable {
@@ -788,18 +820,18 @@ extension Basemap.Style {
788820
return "osmNavigation"
789821
case .osmNavigationDark:
790822
return "osmNavigationDark"
791-
823+
792824
}
793825
}
794826
}
795827

796-
struct MoveToPointsPayload : Codable {
797-
let points : [LatLng]
798-
let padding : Double?
828+
struct MoveToPointsPayload: Codable {
829+
let points: [LatLng]
830+
let padding: Double?
799831
}
800832

801833
extension LoadStatus {
802-
func jsonValue() -> String {
834+
func jsonValue() -> String {
803835
switch self {
804836
case .loaded:
805837
return "loaded"
@@ -818,16 +850,16 @@ extension LoadStatus {
818850
extension String {
819851
func autoPanModeFromString() -> LocationDisplay.AutoPanMode? {
820852
switch self {
821-
case "compassNavigation":
822-
return .compassNavigation
823-
case "navigation":
824-
return .navigation
825-
case "recenter":
826-
return .recenter
827-
case "off":
828-
return .off
829-
default:
830-
return nil
853+
case "compassNavigation":
854+
return .compassNavigation
855+
case "navigation":
856+
return .navigation
857+
case "recenter":
858+
return .recenter
859+
case "off":
860+
return .off
861+
default:
862+
return nil
831863
}
832864
}
833865
}

arcgis_map_sdk_ios/ios/arcgis_map_sdk_ios/Sources/arcgis_map_sdk_ios/CenterPositionStreamHandler.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,8 @@ class CenterPositionStreamHandler: NSObject, FlutterStreamHandler {
2525
func add(center: LatLng) {
2626
sink?(center.dictionary)
2727
}
28+
29+
deinit {
30+
sink = nil
31+
}
2832
}

arcgis_map_sdk_ios/ios/arcgis_map_sdk_ios/Sources/arcgis_map_sdk_ios/ZoomStreamHandler.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,8 @@ class ZoomStreamHandler: NSObject, FlutterStreamHandler {
2929
sink?(zoom)
3030
}
3131
}
32+
33+
deinit {
34+
sink = nil
35+
}
3236
}

0 commit comments

Comments
 (0)