0
votes

so I'm using Mapbox. The map struct conforms to the UIViewRepresentable protocol. In my makeUIView() function, I create a tap gesture recognizer and add it to the map view.

struct Map: UIViewRepresentable {

    private let mapView: MGLMapView = MGLMapView(frame: .zero, styleURL: MGLStyle.streetsStyleURL)

    func makeUIView(context: UIViewRepresentableContext<Map>) -> MGLMapView {
        mapView.delegate = context.coordinator
        let gestureRecognizer = UITapGestureRecognizer(target: context.coordinator, action: Selector("tappedMap"))
        mapView.addGestureRecognizer(gestureRecognizer)
        return mapView
    }

    func updateUIView(_ uiView: MGLMapView, context: UIViewRepresentableContext<Map>) {
        print("Just updated the mapView")
    }

    func makeCoordinator() -> Map.Coordinator {
        Coordinator(appState: appState, self)
    }

    // other functions that make the struct have functions required by Mapbox 

    func makeCoordinator() -> Map.Coordinator {
        Coordinator(self)
    }

    final class Coordinator: NSObject, MGLMapViewDelegate {
        var control: Map

        //a bunch of delegate functions

        @objc func tappedMap(sender: UITapGestureRecognizer) {
            let locationInMap = sender.location(in: control)
            let coordinateSet = sender.convert(locationInMap, toCoordinateFrom: control)
        }
    }
}

Neither of the lines in the tappedMap function compile properly...also, when I have 'sender: UITapGestureRecognizer' in the parameters of tappedMap, I causes the application to crash when I tap the mapView--If I remove the parameter, then the function is at least called properly without crashing. Please help

1
What error/stack trace do you get from the crash? I don't know Mapbox, but I would start with a breakpoint inside tappedMap and inspect the object being received there.John Nimis
@JohnNimis I don't know where the stack trace is in Xcode...sorry kind of a newbie here--the error that is thrown says Thread 1: ........: unrecognizable selector sent to instance and then that's followed with the memory address I think. That leads me to believe that it's not receiving a UITapGestureRecognizer but something else, is that correct? Also if I set a breakpoint on even the first line of the method (when I make the first line a print statement) the error is still thrown so it's something with what the tappedMap function is receiving or how it's being callednickcoding
OK, I'm trying to reproduce the error, but I'm getting a bunch of compiler errors: one is "Class 'Map.Coordinator' has no initializers", and the other have to do with the mapView property, which isn't declared in your code sample. Also, are you importing MapKit in any of these files? You might consider naming your Map struct differently, in case there is some kind of namespace collision.John Nimis
This isn't MapKit, this is MapBox, and you need to have a pod file that imports the correct cocoapodsnickcoding
Yes, I'm aware, and I've imported Mapbox. I asked because MapKit also defines a struct called Map. I only noticed this because my sample project already had some MapKit code in a different file.John Nimis

1 Answers

1
votes

OK, the first problem is your selector definition in the tapGesture declaration. Change it to this:

let gestureRecognizer = UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.tappedMap(sender:)))

Also, you need to manage the priority of gesture recognizers, since MGLMapView includes UIGestureRecognizer logic internally. I found a discussion of here:

Adding your own gesture recognizer to MGLMapView will block the corresponding gesture recognizer built into MGLMapView. To avoid conflicts, define which gesture takes precedence.

You can try this code in your project (pretty much just copied from the linked page above) EDIT: I needed to change the order of lines from my original answer:

let gestureRecognizer = UITapGestureRecognizer(target: context.coordinator, action: Selector("tappedMap"))

// HERE'S THE NEW STUFF:
for recognizer in mapView.gestureRecognizers! where recognizer is UITapGestureRecognizer {
    gestureRecognizer.require(toFail: recognizer)
}

mapView.addGestureRecognizer(gestureRecognizer)

EDIT: I was able to test this.

I'm a little confused by the logic inside your tappedMap selector: maybe you meant something like this?

@objc func tappedMap(sender: UITapGestureRecognizer) {
    let locationInMap = sender.location(in: control.mapView)
    let coordinateSet = sender.view?.convert(locationInMap, to: control.mapView)
}