12

I tried to handle Map UIKit component gestures in SwiftUI application. Xcode shows this warning: "String literal is not a valid Objective-C selector"

// Binding to UIKit component

import SwiftUI
import MapKit

struct MapView: UIViewRepresentable {

    class Coordinator: NSObject, MKMapViewDelegate {
        @Binding var selectedPin: MapPin?

        init(selectedPin: Binding<MapPin?>) {
            self._selectedPin = selectedPin
        }

        func mapView(_ mapView: MKMapView,
                     didSelect view: MKAnnotationView) {
            guard let pin = view.annotation as? MapPin else {
                return
            }
            pin.action?()
            selectedPin = pin
        }

        func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
            guard (view.annotation as? MapPin) != nil else {
                return
            }
            selectedPin = nil
        }
       }

    @Binding var pins: [MapPin]
    @Binding var selectedPin: MapPin?

    func makeCoordinator() -> Coordinator {
      return Coordinator(selectedPin: $selectedPin)
    }

    func makeUIView(context: Context) -> MKMapView {
        let view = MKMapView(frame: .zero)
        let gRecognizer = UITapGestureRecognizer(target: self, action: #selector(triggerTouchAction(gestureRecognizer:)))
          view.addGestureRecognizer(gRecognizer)
          view.delegate = context.coordinator
          return view
    }

    func updateUIView(_ uiView: MKMapView, context: Context) {
        uiView.removeAnnotations(uiView.annotations)
        uiView.addAnnotations(pins)
        if let selectedPin = selectedPin {
            uiView.selectAnnotation(selectedPin, animated: false)
        }
    }

    @objc func triggerTouchAction(gestureReconizer: UITapGestureRecognizer) {
          //Add alert to show it works
        print("Hello, tap!")
    }
}

I expect messages in my Xcode console, but no touch events produced.

Environment: Xcode 11 beta 6 macOS Mojave 10.14.6

Serge Almazov
  • 396
  • 3
  • 11

1 Answers1

16

@objc can't be applied to functions inside structs. Move the function inside the Coordinator and then change the UIGestureRecognizer declaration this way:

let gRecognizer = UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.triggerTouchAction(gestureReconizer:)))
Lorenzo Santini
  • 655
  • 7
  • 13
  • let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(triggerTouchAction(gestureRecognizer:))) Error: Use of unresolved identifier 'triggerTouchAction(gestureRecognizer:) – Serge Almazov Aug 26 '19 at 15:18
  • @ objc func triggerTouchAction(gestureReconizer: UITapGestureRecognizer) { //Add alert to show it works print("Hello, tap!") } Error: @ objc can only be used with members of classes, @ objc protocols, and concrete extensions of classes – Serge Almazov Aug 26 '19 at 15:19
  • I don’t understand your code from the comment...edit your question to include it – Lorenzo Santini Aug 26 '19 at 15:21
  • Where's MapPin declared? – Lorenzo Santini Aug 26 '19 at 15:40
  • How to get Map coordinates in handler? – Serge Almazov Aug 30 '19 at 16:41
  • 1
    @LorenzoSantini Thanks for this. It's great. I implemented a UIPanGestureRecognizer following the same steps, however, my selector is not being called. In looking up why, I've read that because MapKit has gestures implemented as well, it is necessary to add a function for simultaneously using multiple gesture recognizers: func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true }. However, I'm still not having any luck. Can you offer some suggestions please? – Justin Ngan Dec 22 '19 at 04:01