Search code examples
swiftswiftuimapkitgoogle-maps-markers

How to remove a specific Marker in a Map


I set 3 markers (0, 1, 2) in a map (which is on my ContentView). Now I want to remove only the marker 0 (not 1 and not 2).

All I found was "removeAnnotation", although my marker is just a marker, not declared as an annotation. Nevertheless, I took an answer from stack overflow (https://stackoverflow.com/questions/47959193/swift-4-to-remove-only-one-annotation-not-all/47965214, but it doesn't work.

I am rather a beginner in Swift, so the problem seems (beside the removeAnnotation-Question) to be in my code itself.

My code:

import SwiftUI
import MapKit

struct MyLocationsArray: Identifiable {
    let id = UUID()                          
    let number: Int                         
    let name: String                        
    let label: String  
    let coordinates: CLLocationCoordinate2D
    
}


struct ContentView: View {
    
    @State var myLocs = [
        MyLocationsArray(number: 0, name: "name A", label: "label A", coordinates: CLLocationCoordinate2D(latitude: 39.873563, longitude: 3.170857999999953)),
        
        MyLocationsArray(number: 1, name: "name B", label: "label B", coordinates: CLLocationCoordinate2D(latitude: 39.654235, longitude: 2.947624)),
        
        MyLocationsArray(number: 2, name: "name C", label: "label C", coordinates: CLLocationCoordinate2D(latitude: 39.530, longitude: 2.90))
    ]

 
    
    var body: some View {
        Map()
        {
             Marker(myLocs[0].name, coordinate: myLocs[0].coordinates)
             Marker(myLocs[1].name, coordinate: myLocs[1].coordinates)
             Marker(myLocs[2].name, coordinate: myLocs[2].coordinates)
        }
        
        Button("Button title") {
            removeSpecificAnnotation()
        }
        
        
    }
    
    func removeSpecificAnnotation() {
        for n in myLocs {
            
            if let name = n.name, name == "name A" { // "Conditioner for conditional binding must have Optional type, not 'String'": But my "name" ist a String. 
                removeAnnotation(n)   // "Cannot find removeAnnotation in Scope": But with whatelse  can I remove a Marker?
            }
        }
    }
}

I searched through stackoverflow and found an answer, but somehow it doesn't work for my code. In the internet, I didn't find an answer to "how to remove a marker" except to change the pin color to transparent. Ans, as I said, it could also be my general code, as I am a beginner.


Solution

  • In SwiftUI you work with the data, to achieve what you want. In your case, you don't remove the Marker, you remove the data that represents it.

    So try this approach using the data ( myLocs) to select then remove the selected MyLocation, as shown in the example code.

    Select/tap a marker on the map, then press the Remove selected button to remove it from the map

    struct MyLocation: Identifiable, Hashable {
        let id = UUID()
        var number: Int
        var name: String
        var label: String
        var coordinates: CLLocationCoordinate2D
    }
    
    struct ContentView: View {
        
        @State private var myLocs = [
            MyLocation(number: 0, name: "name A", label: "label A", coordinates: CLLocationCoordinate2D(latitude: 39.873563, longitude: 3.170857999999953)),
            MyLocation(number: 1, name: "name B", label: "label B", coordinates: CLLocationCoordinate2D(latitude: 39.654235, longitude: 2.947624)),
            MyLocation(number: 2, name: "name C", label: "label C", coordinates: CLLocationCoordinate2D(latitude: 39.530, longitude: 2.90))
        ]
        
        @State private var selection: MyLocation?
        
        var body: some View {
            Map(selection: $selection) {
                ForEach(myLocs) { loc in
                    Marker(loc.name, coordinate: loc.coordinates).tag(loc)
                }
            }
            Button("Remove selected") {
                removeSelectedMarker()
            }
        }
        
        func removeSelectedMarker() {
            if let index = myLocs.firstIndex(where: {$0.id == selection?.id}){
                myLocs.remove(at: index)
            }
        }
    }
    
    // required for MyLocation Hashable
    extension CLLocationCoordinate2D: Equatable, Hashable {
        public static func == (lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool {
            return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude
        }
        
        public func hash(into hasher: inout Hasher) {
            hasher.combine(latitude)
            hasher.combine(longitude)
        }
    }